1. 程式人生 > >COGS——T2084. Asm.Def的基本算法

COGS——T2084. Asm.Def的基本算法

若有 sin 綠色 重要 turn wap 記憶化 times lld

★☆ 輸入文件:asm_algo.in 輸出文件:asm_algo.out 簡單對比
時間限制:1 s 內存限制:256 MB

【題目描述】

“有句美國俗語說,如果走起來像鴨子,叫起來像鴨子,那就是一只鴨子。”斯科特·華萊士看著Asm.Def面前屏幕上滾動的綠色字符,若有所思地說。

“什麽意思?”

“你的數據。看上去是一棵樹。”

“按照保密條令,我什麽也不說這是最好的——但見你這麽熱情,一句話不說也不好。”Asm.Def停下手中的快速數論變換,“確實是樹。”

“然後你怎麽算出來目標的位置?”

“都需要按照基本算法,按照圖論的那一套理論,去產生。聽說過LCA嗎?不是那個印度飛機,我是說最近公共祖先……”

技術分享

Asm.Def通過分析無線電信號得到了一棵有n個節點,以1為根的樹。除1之外,節點i的父親是p_i。節點帶有權值,節點i的權值是w_i。

我們定義某點的祖先為從根到它路徑上的所有點(包括它本身),而兩個節點a、b的最近公共祖先是某個點p,使得p同時是a、b的祖先,而且p離根最遠。

Asm.Def想要求出

技術分享

(文字:∑∑w_i*w_j*w_LCA(i,j)),

其中LCA(i,j)是i、j的最近公共祖先,他認為這個值至關重要。由於這個值可能很大,Asm.Def只需要知道它模1,000,000,007(即10^9+7)的結果。

【輸入格式】

第1行兩個整數:n和w_1.

第2行到第n行,第i行有兩個整數p_i和w_i。

【輸出格式】

一行一個整數,即答案模1,000,000,007的值。

【樣例輸入】

2 2
1 1

【樣例輸出】

17

【提示】

1×1×1+1×2×2+2×1×2+2×2×2=17。

對於30%的數據,n<=100,w_i<=10。

對於60%的數據,n<=1000,w_i<=1000.

對於100%的數據,1<=n<=10^5,0<=w_i<=10^9,1<=p_i<i.

裸LCA只能拿60分後面就超時了

技術分享
 1 #include <algorithm>
 2 #include <cstdio>
 3  
 4 #define mod 1000000007
 5  
 6 using namespace std;
 7  
 8 const int N(1e6+15);
 9 int n,x,ans,w[N],a[N];
10  
11 int sumedge,head[N];
12 struct Edge
13 {
14     int from,to,next;
15     Edge(int from=0,int to=0,int next=0):from(from),to(to),next(next){}
16 }edge[N];
17 void ins(int from,int to)
18 {
19     edge[++sumedge]=Edge(from,to,head[from]);
20     head[from]=sumedge;
21 }
22  
23 int deep[N],size[N],dad[N],top[N];
24 void DFS(int x)
25 {
26     deep[x]=deep[dad[x]]+1;size[x]=1;
27     for(int i=head[x];i;i=edge[i].next)
28     {
29         int to=edge[i].to;
30         if(dad[x]!=to)
31             dad[to]=x,DFS(to),size[x]+=size[to];
32     }
33 }
34 void DFS_(int x)
35 {
36     int t=0;if(!top[x]) top[x]=x;
37     for(int i=head[x];i;i=edge[i].next)
38     {
39         int to=edge[i].to;
40         if(dad[x]!=to&&size[t]<size[to]) t=to;
41     }
42     if(t) top[t]=top[x],DFS_(t);
43     for(int i=head[x];i;i=edge[i].next)
44     {
45         int to=edge[i].to;
46         if(dad[x]!=to&&t!=to) DFS_(to);
47     }
48 }
49  
50 int LCA(int x,int y)
51 {
52     for(;top[x]!=top[y];x=dad[top[x]])
53         if(deep[top[x]]<deep[top[y]]) swap(x,y);
54     return deep[x]>deep[y]?y:x;
55 }
56  
57 int main()
58 {
59     freopen("asm_algo.in","r",stdin);
60     freopen("asm_algo.out","w",stdout);
61     scanf("%d%d",&n,&w[1]);
62     for(int i=2;i<=n;i++)
63         scanf("%d%d",&x,w+i),ins(i,x),ins(x,i);
64     DFS(1); DFS_(1);
65     for(int i=1;i<=n;i++)
66       for(int j=1;j<=n;j++)
67         ans=(ans%mod+(w[i]*w[j]*w[LCA(i,j)])%mod)%mod;
68     printf("%d",ans);
69     return 0;
70 }
AAAAAATTTT

容易發現每個點自身的值都會加上,剩下的可以用記憶化搜索求出來

技術分享
 1 #include <algorithm>
 2 #include <cstdio>
 3  
 4 #define mod 1000000007
 5 #define LL long long
 6 
 7 using namespace std;
 8  
 9 const LL N(1e5+15);
10 LL n,x,w[N];
11  
12 LL sumedge,head[N];
13 struct Edge
14 {
15     LL from,to,next;
16     Edge(LL from=0,LL to=0,LL next=0):from(from),to(to),next(next){}
17 }edge[N];
18 void ins(LL from,LL to)
19 {
20     edge[++sumedge]=Edge(from,to,head[from]);
21     head[from]=sumedge;
22 }
23 
24 LL sum[N],dad[N],ans;
25 void DFS(LL x)
26 {
27     sum[x]=w[x];
28     for(LL i=head[x];i;i=edge[i].next)
29     {
30         LL to=edge[i].to;
31         if(!dad[to])
32         {
33             dad[to]=x; DFS(to);
34             ans=(ans%mod+sum[x]%mod*sum[to]%mod*w[x]%mod)%mod;
35             sum[x]=(sum[x]%mod+sum[to]%mod)%mod;
36         }
37     }
38 }
39  
40 int main()
41 {
42     freopen("asm_algo.in","r",stdin);
43     freopen("asm_algo.out","w",stdout);
44     scanf("%lld%lld",&n,&w[1]);
45     for(LL i=2;i<=n;i++)
46         scanf("%lld%lld",&x,w+i), ins(x,i);
47     DFS(1); ans=ans%mod*2%mod;
48     for(LL i=1;i<=n;i++)
49         ans=(ans%mod+w[i]%mod*w[i]%mod*w[i]%mod)%mod;
50     printf("%lld",ans%mod);
51     return 0;
52 }
AAAAAAAAAA

COGS——T2084. Asm.Def的基本算法