1. 程式人生 > >cogs2274[HEOI 2016] tree【解題報告】

cogs2274[HEOI 2016] tree【解題報告】

add spl 我們 eve clu 一個 pac load void

鏈接

技術分享圖片

技術分享圖片

技術分享圖片

官方的數據很水,暴力可a,2332是加強版。

算法:並查集

思路:如果我們按詢問順著來弄,並查集將無法實現,因為一個點一旦指向了深度更小的點,就再也無法指回深度較大的點了。所以我們考慮倒序處理。

先將所有的操作離線,對所有修改操作進行實現,然後dfs求出每個點的祖先中最近的被標記點,可以在O(n)的時間內實現。

然後考慮倒著往回操作,每一次查詢只需記錄下來被查詢點的最終父親是誰。而每一次修改操作就是將w[x]--,一旦w[x]變為0了,意味著他不再被標記了。

那麽我們就讓他指向他相鄰的那個父親的最終父親即可。

技術分享圖片
 1 #include<bits/stdc++.h>
 2
using namespace std; 3 const int inf=1e6+1; 4 int n,q,w[inf]; 5 int fa[inf],last[inf]; 6 int fi[inf],tot,to[inf<<1],next[inf<<1]; 7 void edge_add(int x,int y){ 8 to[++tot]=y; 9 next[tot]=fi[x]; 10 fi[x]=tot; 11 } 12 void dfs(int x,int f){ 13 fa[x]=f; 14
if(w[x])last[x]=x; 15 else last[x]=last[fa[x]]; 16 for(int i=fi[x];i;i=next[i]){ 17 if(to[i]==f)continue; 18 dfs(to[i],x); 19 } 20 } 21 struct Q{ 22 int x,ans; 23 char c; 24 void read(){ 25 char s[5]; 26 scanf("%s%d",s,&x);
27 c=s[0]; 28 } 29 }g[inf]; 30 void init(int x){ 31 g[x].read(); 32 if(g[x].c==C){ 33 w[g[x].x]++; 34 } 35 } 36 int get_last(int x){ 37 return w[x]?x:last[x]=get_last(last[x]); 38 } 39 int main() 40 { 41 freopen("tree++.in","r",stdin); 42 freopen("tree++.out","w",stdout); 43 scanf("%d%d",&n,&q); 44 for(int i=1;i<n;i++){ 45 int x,y; 46 scanf("%d%d",&x,&y); 47 edge_add(x,y);edge_add(y,x); 48 } 49 w[1]=1; 50 for(int i=1;i<=q;i++){ 51 init(i); 52 } 53 dfs(1,0); 54 for(int i=q;i>=1;i--){ 55 if(g[i].c==C){ 56 w[g[i].x]--; 57 if(!w[g[i].x])last[g[i].x]=get_last(fa[g[i].x]); 58 } 59 else { 60 g[i].ans=get_last(g[i].x); 61 } 62 } 63 for(int i=1;i<=q;i++){ 64 if(g[i].c==Q){ 65 printf("%d\n",g[i].ans); 66 } 67 } 68 return 0; 69 }
代碼君

cogs2274[HEOI 2016] tree【解題報告】