題面:https://www.luogu.org/problemnew/lists?name=2146html
這道題就是樹鏈剖分的模板,詳細解釋見程序。ios
學完樹的dfs序,lca,線段樹食用更佳。c++
不會這些學什麼樹剖(逃~spa
#include <bits/stdc++.h> //萬能頭文件 using namespace std; int n,q,tot; int fa[100005],size[100005],dep[100005],son[100005]; int lo[100005],top[100005]; int sum[800005],tag[800005]; vector <int> allson[100005]; //線段樹 void pushup(int x)//更新 { sum[x]=sum[x<<1]+sum[(x<<1)+1]; } void pushdown(int x,int l,int r)//清除懶標記 { if(tag[x]!=-1) { int m=(l+r)>>1; int ls=x<<1; int rs=ls+1; tag[ls]=tag[rs]=tag[x]; sum[ls]=(m-l+1)*tag[x]; sum[rs]=(r-m)*tag[x]; tag[x]=-1; } } void update(int x,int l,int r,int L,int R,int v)//修改 { if(R<l||r<L) return; if(L<=l&&r<=R) { sum[x]=(r-l+1)*v; tag[x]=v; return; } pushdown(x,l,r); int m=(l+r)>>1; update(x<<1,l,m,L,R,v); update((x<<1)+1,m+1,r,L,R,v); pushup(x); } //樹鏈剖分 void change(int x,int y,int v)//相似lca { int fx=top[x],fy=top[y]; while(fx!=fy) { if(dep[fx]<dep[fy]) swap(x,y),swap(fx,fy); update(1,1,tot,lo[fx],lo[x],v); x=fa[fx],fx=top[x]; } if(lo[x]>lo[y]) swap(x,y); update(1,1,tot,lo[x],lo[y],v); } void dfs1(int x) { size[x]=1; for(int i=0;i<allson[x].size();++i) { int v=allson[x][i]; dep[v]=dep[x]+1;//深度 dfs1(v); size[x]+=size[v];//子樹大小 if(size[v]>size[son[x]]) son[x]=v;//重兒子 } } void dfs2(int x,int t) { lo[x]=++tot; top[x]=t;//重鏈父親 if(son[x]) dfs2(son[x],t); for(int i=0;i<allson[x].size();++i) { int v=allson[x][i]; if(v!=son[x]) dfs2(v,v); } } int main() { memset(tag,-1,sizeof(tag)); //lazy_tag爲-1表示沒有 ios::sync_with_stdio(0); cin>>n; fa[1]=1; for(int i=2;i<=n;++i) { int x; cin>>x; fa[i]=x+1; allson[x+1].push_back(i); } //預處理 dfs1(1); dfs2(1,1); cin>>q; while(q--) { string s; int x; cin>>s>>x; x++; int before=sum[1];//改以前 if(s=="install") { change(1,x,1);//1到x路上全改爲1 int after=sum[1];//改後 cout<<fabs(before-after)<<endl; } else { update(1,1,n,lo[x],lo[x]+size[x]-1,0);//把x的子樹改爲0 int after=sum[1];//改後 cout<<fabs(before-after)<<endl; } } return 0; }