【Foreign】采蘑菇 [点分治]
采蘑菇
Time Limit: 20 Sec??Memory Limit: 256 MBDescription
Input
Output
Sample Input
51 2 3 2 3
1 2
1 3
2 4
2 5
Sample Output
109
12
9
11
HINT
Main idea
詢問從以每個點為起始點時,各條路徑上的顏色種類的和。
Solution
我們看到題目,立馬想到了O(n^2)的做法,然后從這個做法研究一下本質(zhì),我們確定了可以以點分治作為框架。
我們先用點分治來確定一個center(重心)。然后計算跟這個center有關(guān)的路徑。設(shè)現(xiàn)在要統(tǒng)計的是經(jīng)過center,對x提供貢獻的路徑。
我們先記錄一個記錄Sum[x]表示1~i-1子樹中 顏色x 第一次出現(xiàn)的位置的那個點 的子樹和,然后我們就利用這個Sum來解題。
我們顯然可以分兩種情況來討論:
(1)統(tǒng)計center->x出現(xiàn)顏色的貢獻:
顯然,這時候,對于center->x這一段,直接像O(n^2)做法那樣記錄一個color表示到目前為止出現(xiàn)的顏色個數(shù),然后加一下即可。再記錄一個record表示當前可有的貢獻和,一旦出現(xiàn)過一個顏色,那么這個顏色在1~i-1子樹上出現(xiàn)第一次以下的點,對于x就不再提供貢獻了,record減去Sum[這個顏色],然后這樣深搜往下計算即可。
(2)統(tǒng)計center->x沒出現(xiàn)過的顏色的貢獻:
顯然,對于center->x上沒出現(xiàn)過的顏色,直接往下深搜,一開始為record為(All - Sum[center]),一旦出現(xiàn)了一個顏色,record則減去這個Sum。同樣表示不再提供貢獻即可。
我們這樣做就可以求出每個子樹前綴對于其的貢獻了,倒著再做一邊即可求出全部的貢獻。統(tǒng)計x的時候,順便統(tǒng)計一下center。可以滿足效率,成功AC這道題。
Code
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<cstdlib> 6 #include<cmath> 7 using namespace std; 8 9 const int ONE = 600005; 10 const int INF = 214783640; 11 const int MOD = 1e9+7; 12 13 int n,x,y; 14 int Val[ONE]; 15 int next[ONE],first[ONE],go[ONE],tot; 16 int vis[ONE]; 17 int Ans[ONE],Sum[ONE]; 18 int All; 19 20 21 int get() 22 { 23 int res,Q=1; char c; 24 while( (c=getchar())<48 || c>57) 25 if(c=='-')Q=-1; 26 if(Q) res=c-48; 27 while((c=getchar())>=48 && c<=57) 28 res=res*10+c-48; 29 return res*Q; 30 } 31 32 void Add(int u,int v) 33 { 34 next[++tot]=first[u]; first[u]=tot; go[tot]=v; 35 next[++tot]=first[v]; first[v]=tot; go[tot]=u; 36 } 37 38 namespace Point 39 { 40 int center; 41 int Stack[ONE],top; 42 int total,Max,center_vis[ONE]; 43 int num,V[ONE]; 44 45 struct power 46 { 47 int size,maxx; 48 }S[ONE]; 49 50 void Getsize(int u,int father) 51 { 52 S[u].size=1; 53 S[u].maxx=0; 54 for(int e=first[u];e;e=next[e]) 55 { 56 int v=go[e]; 57 if(v==father || center_vis[v]) continue; 58 Getsize(v,u); 59 S[u].size += S[v].size; 60 S[u].maxx = max(S[u].maxx,S[v].size); 61 } 62 } 63 64 void Getcenter(int u,int father,int total) 65 { 66 S[u].maxx = max(S[u].maxx,total-S[u].size); 67 if(S[u].maxx < Max) 68 { 69 Max = S[u].maxx; 70 center = u; 71 } 72 73 for(int e=first[u];e;e=next[e]) 74 { 75 int v=go[e]; 76 if(v==father || center_vis[v]) continue; 77 Getcenter(v,u,total); 78 } 79 } 80 81 void Ad_sum(int u,int father) 82 { 83 if(!vis[Val[u]]) 84 { 85 Stack[++top] = Val[u]; 86 All += S[u].size; Sum[Val[u]] += S[u].size; 87 } 88 vis[Val[u]]++; 89 for(int e=first[u];e;e=next[e]) 90 { 91 int v=go[e]; 92 if(v==father || center_vis[v]) continue; 93 Ad_sum(v,u); 94 } 95 vis[Val[u]]--; 96 } 97 98 void Calc_in(int u,int father,int center,int Size,int f_time,int record) 99 { 100 if(!vis[Val[u]]) f_time++, record += Size, record -= Sum[Val[u]]; 101 Ans[u] += record; Ans[center]+=f_time; 102 Ans[u] += f_time; vis[Val[u]] ++; 103 for(int e=first[u];e;e=next[e]) 104 { 105 int v=go[e]; 106 if(v==father || center_vis[v]) continue; 107 Calc_in(v,u,center,Size,f_time,record); 108 } 109 vis[Val[u]] --; 110 } 111 112 void Calc_not(int u,int father,int record) 113 { 114 if(!vis[Val[u]]) record -= Sum[ Val[u] ]; 115 Ans[u] += record; vis[Val[u]] ++; 116 for(int e=first[u];e;e=next[e]) 117 { 118 int v=go[e]; 119 if(v==father || center_vis[v]) continue; 120 Calc_not(v,u,record); 121 } 122 vis[Val[u]] --; 123 } 124 125 void Dfs(int u) 126 { 127 Max = n; 128 Getsize(u,0); 129 Getcenter(u,0,S[u].size); 130 Getsize(center,0); 131 center_vis[center] = 1; 132 133 int num=0; for(int e=first[center];e;e=next[e]) if(!center_vis[go[e]]) V[++num]=go[e]; 134 135 for(int i=1;i<=num;i++) 136 { 137 int v=V[i]; 138 int Size = S[center].size - S[v].size - 1; 139 vis[Val[center]] = 1; 140 Calc_in(v,center,center, Size,1,All - Sum[Val[center]] + Size); 141 vis[Val[center]] = 0; 142 Ad_sum(v,center); 143 } 144 while(top) Sum[Stack[top--]]=0; All=0; 145 146 for(int i=num;i>=1;i--) 147 { 148 int v=V[i]; 149 vis[Val[center]] = 1; 150 Calc_not(v,center, All-Sum[Val[center]]); 151 vis[Val[center]] = 0; 152 Ad_sum(v,center); 153 } 154 155 while(top) Sum[Stack[top--]]=0; All=0; 156 for(int e=first[center];e;e=next[e]) 157 { 158 int v=go[e]; 159 if(center_vis[v]) continue; 160 Dfs(v); 161 } 162 } 163 164 } 165 166 int main() 167 { 168 n=get(); 169 for(int i=1;i<=n;i++) Val[i]=get(); 170 171 for(int i=1;i< n;i++) 172 { 173 x=get(); y=get(); 174 Add(x,y); 175 } 176 177 Point:: Dfs(1); 178 for(int i=1;i<=n;i++) 179 printf("%d\n",Ans[i]+1); 180 } View Code?
轉(zhuǎn)載于:https://www.cnblogs.com/BearChild/p/6517325.html
總結(jié)
以上是生活随笔為你收集整理的【Foreign】采蘑菇 [点分治]的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java避免内存泄露_Java防止非静态
- 下一篇: 面试进阶题集锦-持续更新