四年前的noi我现在还切不掉我觉得我可以退役了
题目链接:https://www.luogu.org/problem/P2146
题目大意:不想写了
树剖,记下重儿子,然后用线段树维护一下就AC了
#include<bits/stdc++.h> using namespace std; const int MAXN=400010; priority_queue<int> Q; char c[20]; int T,kk,n,m,head[MAXN],ver[MAXN],nxt[MAXN],tot,fa[MAXN],dep[MAXN],son[MAXN],top[MAXN],pps[MAXN],sz[MAXN],tot2,sum[MAXN],lz[MAXN],x,bf; void add(int x,int y){ ver[++tot]=y; nxt[tot]=head[x]; head[x]=tot; }void dfs1(int x){ dep[x]=dep[fa[x]]+1,sz[x]=1; for (int i=head[x];i;i=nxt[i]){ if (ver[i]==fa[x]) continue; fa[ver[i]]=x;dfs1(ver[i]);sz[x]+=sz[ver[i]]; if (sz[ver[i]]>sz[son[x]]) son[x]=ver[i]; } }void dfs2(int x,int fa){ pps[x]=++tot2,top[x]=fa; if (!son[x]) return; dfs2(son[x],fa); for (int i=head[x];i;i=nxt[i]) if(!pps[ver[i]]) dfs2(ver[i],ver[i]); }void upp(int x){sum[x]=sum[x<<1]+sum[x<<1|1];} void pushdown(int i,int l,int r){ if (lz[i]==0) return;int mid=l+r>>1; if (lz[i]==-1) sum[i<<1]=sum[i<<1|1]=0,lz[i<<1]=lz[i<<1|1]=-1; else sum[i<<1]=mid-l+1,sum[i<<1|1]=r-mid,lz[i<<1]=lz[i<<1|1]=1; lz[i]=0;return; }void update(int i,int l,int r,int ql,int qr,int x){ if (ql<=l&&r<=qr){ if (!x)lz[i]=-1,sum[i]=0; else lz[i]=1,sum[i]=r-l+1; return; }int mid=l+r>>1;pushdown(i,l,r); if (mid>=ql) update(i<<1,l,mid,ql,qr,x); if (mid<qr) update(i<<1|1,mid+1,r,ql,qr,x); upp(i); }void change(int v,int x,int y){ while (top[x]!=top[y]){ if (dep[top[x]]<dep[top[y]]) swap(x,y); update(1,1,n,pps[top[x]],pps[x],v); x=fa[top[x]]; }if (dep[x]>dep[y]) swap(x,y); update(1,1,n,pps[x],pps[y],v); }int main(){ scanf("%d",&n); for (int i=2;i<=n;i++){ scanf("%d",&kk); add(++kk,i);add(i,kk); }scanf("%d",&T);dfs1(1),dfs2(1,1); while (T--){ cin>>c+1;scanf("%d",&kk);bf=sum[1];++kk; if (c[1]=='i'){ change(1,kk,1); printf("%d ",abs(sum[1]-bf)); }else{ update(1,1,n,pps[kk],pps[kk]+sz[kk]-1,0); printf("%d ",abs(sum[1]-bf)); } }return 0; }