P2146 [NOI2015]软件包管理器
树剖入门题
题目大意:
操作一:把u到根节点的路径全部点亮
操作二:把u以及所有u的子树节点熄灭
求每一次操作之后改变了多少点的亮暗?
裸的树剖,对于我这样的菜鸡入门人士十分合适
大力树剖时,跳链是最关键的(其实线段树不怎么难,大概PJ难度)
il void cgn(int x,int y,int SUM){ while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); T.upd(1,n,1,dfn[top[x]],dfn[x],SUM); x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y); T.upd(1,n,1,dfn[x],dfn[y],SUM); }
大力跳链代码
第一次 if(dep[top[x]]<dep[top[y]]) swap(x,y); 打错了,没有加"top"
这是一个本质错误,对于跳链过程,比的是一整条链,而不是单个点
其他没什么好说的了
代码:
#include<bits/stdc++.h> using namespace std; #define il inline const int N=100005; int n,m; int fa[N];//父亲编号 int size[N];//子树大小 int son[N];//重儿子编号 int dep[N];//节点深度 int belong[N];//所属重链 int cont=0;//重链条数 int top[N];//节点所在重链链顶 int dfn[N];//dfs序 int indexy=0;//时间戳 int rk[N];//dfs序对应原节点 int hed[N],tal[N<<1],val[N<<1],nxt[N<<1],cnt=0; struct Sugment_Tree{ int t[N<<2];//安装的个数 int LZT[N<<2];//懒标记 #define mid (l+r)/2 Sugment_Tree(){memset(LZT,-1,sizeof(LZT));} il void push_up(int num){ t[num]=t[num<<1]+t[num<<1|1]; } il void push_down(int l,int r,int num){//懒标记下传 if(LZT[num]==-1) return; LZT[num<<1]=LZT[num]; LZT[num<<1|1]=LZT[num]; t[num<<1]=(mid-l+1)*LZT[num]; t[num<<1|1]=(r-(mid+1)+1)*LZT[num]; LZT[num]=-1; } il void build(int l,int r,int num){ if(l==r){ t[num]=0; return; } build(l,mid,num<<1); build(mid+1,r,num<<1|1); push_up(num); } il void upd(int l,int r,int num,int L,int R,int SUM){ if(l>R||r<L) return; if(l>=L&&r<=R){ t[num]=(r-l+1)*SUM;//反转 LZT[num]=SUM; return; } push_down(l,r,num); upd(l,mid,num<<1,L,R,SUM); upd(mid+1,r,num<<1|1,L,R,SUM); push_up(num); } il int ask(int l,int r,int num,int L,int R){//询问区间1的个数 if(l>R||r<L) return 0; if(l>=L&&r<=R) return t[num]; push_down(l,r,num); return ask(l,mid,num<<1,L,R)+ask(mid+1,r,num<<1|1,L,R); } }T; il void dfs1(int u){ size[u]=1; for(int i=hed[u];i;i=nxt[i]){ int v=tal[i]; if(v==fa[u]) continue; dep[v]=dep[u]+1; dfs1(v); size[u]+=size[v]; if(size[v]>size[son[u]]) son[u]=v; } } il void dfs2(int u,int t){ top[u]=t; dfn[u]=++indexy; rk[dfn[u]]=u; if(!son[u]) return; dfs2(son[u],t); for(int i=hed[u];i;i=nxt[i]){ int v=tal[i]; if(v==fa[u]||v==son[u]) continue; dfs2(v,v); } } il void addege(int x,int y){ cnt++; tal[cnt]=y; nxt[cnt]=hed[x]; hed[x]=cnt; } il void cgn(int x,int y,int SUM){ while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); T.upd(1,n,1,dfn[top[x]],dfn[x],SUM); x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y); T.upd(1,n,1,dfn[x],dfn[y],SUM); } int main(){ scanf("%d",&n); for(int i=2;i<=n;i++){ int x; scanf("%d",&x); ++x; fa[i]=x;//处理父亲 addege(x,i); addege(i,x); } dep[1]=1; dfs1(1);//第一遍dfs dfs2(1,1); T.build(1,n,1); scanf("%d",&m); for(int i=1;i<=m;i++){ char c; int x; cin>>c; int val1,val2; val1=T.t[1]; if(c=='i'){ cin>>c>>c>>c>>c>>c>>c; scanf("%d",&x);//操作子树 x++; cgn(1,x,1); val2=T.t[1]; printf("%d\n",abs(val1-val2)); } else{ cin>>c>>c>>c>>c>>c>>c>>c>>c; scanf("%d",&x); x++; T.upd(1,n,1,dfn[x],dfn[x]+size[x]-1,0); val2=T.t[1]; printf("%d\n",abs(val1-val2)); } } return 0; }