P4092 [HEOI2016/TJOI2016]樹 題解
阿新 • • 發佈:2020-11-01
Link
Solve
這道題是一個樹剖顯然能解決的問題,但是lyz神仙非要離線做懶得寫樹剖
考慮離線做,一個點把一條鏈分成兩部分,比較類似於刪邊的操作,對於只有刪邊,我們就可以考慮倒過來處理,就只有連邊了,用並查集來維護
如果最後是被標記過的點,把\(fa[]\)標為自己,否則標記為父節點。
反過來處理,如果詢問,直接獲取\(get(x)\)就是答案,如果是標記,就\(vis[x]--\),如果\(vis[x]\)被減到\(0\)了,說明這條鏈已經被打通了,就把\(fa[x]\)改為自己的父親
還有一個細節,1號節點沒有父節點,所以在\(vis[x]--\)
Code
#include<bits/stdc++.h> using namespace std; const int maxn=100005,maxe=200005; int N,fa[maxn],Q,ans[maxn],lnk[maxn],cnt,nxt[maxe],son[maxe],vis[maxn],fa_tree[maxn]; struct query{ char op; int x; }q[maxn]; inline int read(){ int ret=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();} while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar(); return ret*f; } inline char read_ch(){ char ch=getchar(); while(ch!='C'&&ch!='Q')ch=getchar(); return ch; } inline void add_e(int x,int y){son[++cnt]=y;nxt[cnt]=lnk[x];lnk[x]=cnt;} void DFS(int x,int f){ fa[x]=(vis[x]||x==1)?x:fa_tree[x]; for(int j=lnk[x];j;j=nxt[j]){ if(son[j]==f)continue; fa_tree[son[j]]=x; DFS(son[j],x); } return ; } int get(int x){return fa[x]==x?x:fa[x]=get(fa[x]);} int main(){ freopen("P4092.in","r",stdin); freopen("P4092.out","w",stdout); N=read();Q=read(); for(int i=1;i<N;i++){ int x=read(),y=read(); add_e(x,y);add_e(y,x); } for(int i=1;i<=Q;i++){ q[i].op=read_ch();q[i].x=read(); if(q[i].op=='C')vis[q[i].x]++; } DFS(1,0);vis[1]++; for(int i=Q;i;i--){ if(q[i].op=='C'){ if(!--vis[q[i].x])fa[q[i].x]=fa_tree[q[i].x]; } else { ans[++ans[0]]=get(q[i].x); } } for(int i=ans[0];i;i--)printf("%d\n",ans[i]); return 0; }