题面: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; }