不,你想多了,我並沒有發明.
動態樹?我會LCT!
然後加上在線和可持久化的前綴,這道題就變得面目可憎了起來.
對於一個森林,剛開始沒有邊.你需要維護下面的操作.
操作1:給定x,y,令x的父親爲y.
操作2:給定t,x,k,求第t個版本中x的第k個祖先.如果沒有輸出0.
操作3:給定t,x,求第t個版本中x的深度.
20%:n<=100,m<=500,強制在線.
另外30%:不強制在線.
100%:n<=100000,m<=500000,有可能強制在線.
那麼只說一下離線的好了.
這拿頭寫啊?看下面的題了.然後發現下面的題更難.於是回來想這道怎麼做.
20分貌似很好拿.維護每個版本每個節點的父親,每個詢問就O(n)的往上跳就完事了.
然後開始剩下的70分怎麼辦.想到了想LCT,但是可持久化解決不了.LCT一會拆開一會旋轉的,不好搞.我還會什麼數據結構呢?我會樹鏈剖分!於是離線的30分就有了:先做出來最後的樹的樹鏈.用線段樹維護樹鏈區間的下標和最大時間戳.跑的時候,如果"版本號"<時間戳就不能過去,遞歸一個子區間即可.很穩的mlogn^2.
開始寫的時候,我想到,我只需要維護區間最大時間戳,爲什麼不寫遞增呢?
先全部讀入,用倍增的思想預處理出每個節點x的第2^k祖先fa[x][k]和這條路徑上的最大時間戳maxx[x][k].每次詢問就每次開開心心的跳就完事了.
using namespace std; int n; namespace _20 { int m,x,tx,ty,fa[110][500010],u,t,ans,op,k; int lastans; } namespace _30 { int m; struct ASK { int op,t,u,k; }o[500010]; int t,tx,ty,k,u; int fa[100010][25],maxx[100010][25]; } int main() { freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); n=read(); if(n<=100) { using namespace _20; m=read();x=read(); for(int i=1;i<=m;i++) { for(int f=1;f<=n;f++) fa[f][i]=fa[f][i-1]; op=(read()+lastans*x)%3; if(op==0) { tx=(read()+lastans*x)%n+1;ty=(read()+lastans*x)%n+1; fa[tx][i]=ty; } else if(op==1) { t=(read()+lastans*x)%m;u=(read()+lastans*x)%n+1;k=(read()+lastans*x)%n; while(fa[u][t]&&k) { u=fa[u][t]; k--; } if(k!=0) lastans=0; else lastans=u; write(lastans); } else { t=(read()+lastans*x)%m;u=(read()+lastans*x)%n+1; k=0; while(fa[u][t]) { k++; u=fa[u][t]; } lastans=k; write(k); } } return 0; } else { using namespace _30; m=read();t=read(); for(int i=1;i<=m;i++) { o[i].op=read()%3; if(o[i].op==0) { tx=read()%n+1; ty=read()%n+1; fa[tx][0]=ty; maxx[tx][0]=i; } else if(o[i].op==1) { o[i].t=read()%m; o[i].u=read()%n+1; o[i].k=read()%n; } else { o[i].t=read()%m; o[i].u=read()%n+1; } } for(t=1;t<=20;t++) { for(int i=1;i<=n;i++) { fa[i][t]=fa[fa[i][t-1]][t-1]; maxx[i][t]=max(maxx[i][t-1],maxx[fa[i][t-1]][t-1]); } } for(int i=1;i<=m;i++) { hear: if(o[i].op==1) { t=o[i].t; u=o[i].u; k=o[i].k; if(k==0) { write(u); continue; } for(int f=20;f>=0;f--) { if(k>=(1<<f)) { if(maxx[u][f]>t) { write(0); i++; if(i<=m) goto hear; else return 0; } u=fa[u][f]; k-=(1<<f); } } write(u); } else if(o[i].op==2) { t=o[i].t; u=o[i].u; k=0; for(int f=20;f>=0;f--) { if(maxx[u][f]<=t&&fa[u][f]) { u=fa[u][f]; k+=(1<<f); } } write(k); } } return 0; } }