P2146 [NOI2015]软件包管理器
树剖入门题
题目大意:
操作一:把u到根节点的路径全部点亮
操作二:把u以及所有u的子树节点熄灭
求每一次操作之后改变了多少点的亮暗?
裸的树剖,对于我这样的菜鸡入门人士十分合适
大力树剖时,跳链是最关键的(其实线段树不怎么难,大概PJ难度)
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"
这是一个本质错误,对于跳链过程,比的是一整条链,而不是单个点
其他没什么好说的了
代码:
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;
}
知识兔