P4332-[SHOI2014]三叉神經樹【LCT】
阿新 • • 發佈:2021-07-18
正題
題目連結:https://www.luogu.com.cn/problem/P4332
題目大意
給出\(n\)個點的一棵有根三叉樹,保證每個點的兒子個數為\(3\)或者\(0\),每個葉子有一個權值\(0\)或\(1\),每個非葉子節點的權值是它兒子中權值較多的那個,每次修改一個葉子的權值,求根節點的權值。
\(1\leq n,q\leq 5\times 10^5\)
解題思路
修改一個節點會影響的權值顯然是它到根節點路徑上的一個字首。
然後考慮什麼樣的節點會受到影響,如果\(0\)改為\(1\)那麼一路上原來恰好為兩個\(0\)的節點就會被修改,那麼我們的思路是考慮找到這條路徑上第一個\(1\)的個數不為\(1\)
而且考慮上修改的話十分的麻煩,因為\(O(n\log^2 n)\)過不去所以不考慮樹剖,可以考慮一下\(LCT\)。
我們可以先聯通修改點到根的節點,然後在\(Splay\)上二分出第一個不為\(1\)的節點,然後對於它和它的右子樹暴力修改即可。
\(1\)改為\(0\)同理,維護第一個不為\(2\)的節點即可。
時間複雜度\(O(n\log n)\)
code
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<stack> using namespace std; const int N=2e6+10; int n,m,ans,fa[N],v[N],w1[N],w2[N],lazy[N],t[N][2]; vector<int> G[N];stack<int> s; bool Nroot(int x) {return fa[x]&&(t[fa[x]][0]==x||t[fa[x]][1]==x);} bool Direct(int x) {return t[fa[x]][1]==x;} void PushUp(int x){ if(w1[t[x][1]])w1[x]=w1[t[x][1]]; else if(v[x]!=1)w1[x]=x; else w1[x]=w1[t[x][0]]; if(w2[t[x][1]])w2[x]=w2[t[x][1]]; else if(v[x]!=2)w2[x]=x; else w2[x]=w2[t[x][0]]; return; } void PushR(int x,int w) {v[x]^=3;swap(w1[x],w2[x]);lazy[x]+=w;return;} void PushDown(int x){ if(!lazy[x])return; PushR(t[x][0],lazy[x]); PushR(t[x][1],lazy[x]); lazy[x]=0;return; } void Rotate(int x){ int y=fa[x],z=fa[y]; int xs=Direct(x),ys=Direct(y); int w=t[x][xs^1]; if(Nroot(y))t[z][ys]=x; t[x][xs^1]=y;t[y][xs]=w; if(w)fa[w]=y;fa[y]=x;fa[x]=z; PushUp(y);PushUp(x);return; } void Splay(int x){ int y=x;s.push(x); while(Nroot(y))y=fa[y],s.push(y); while(!s.empty())PushDown(s.top()),s.pop(); while(Nroot(x)){ y=fa[x]; if(!Nroot(y))Rotate(x); else if(Direct(x)==Direct(y)) Rotate(y),Rotate(x); else Rotate(x),Rotate(x); } return; } void Access(int x){ for(int y=0;x;y=x,x=fa[x]) Splay(x),t[x][1]=y,PushUp(x); return; } void Updata(int x){ int op=(v[x]^=2); x=fa[x];Access(x);Splay(x); if(op){ if(w1[x]){ x=w1[x];Splay(x); PushR(t[x][1],1);PushUp(t[x][1]); v[x]++;PushUp(x); } else ans=!ans,PushR(x,1),PushUp(x); } else{ if(w2[x]){ x=w2[x];Splay(x); PushR(t[x][1],-1);PushUp(t[x][1]); v[x]--;PushUp(x); } else ans=!ans,PushR(x,-1),PushUp(x); } return; } void dfs(int x){ for(int i=0;i<G[x].size();i++){ int y=G[x][i];dfs(y); v[x]+=(v[y]>>1); } PushUp(x); return; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); fa[x]=fa[y]=fa[z]=i; G[i].push_back(x); G[i].push_back(y); G[i].push_back(z); } for(int i=n+1;i<=3*n+1;i++) scanf("%d",&v[i]),v[i]<<=1; dfs(1);ans=v[1]>>1; scanf("%d",&m); while(m--){ int x;scanf("%d",&x); Updata(x); printf("%d\n",ans); } return 0; }