[NOI2015] 软件包管理器

Luogu
LOJ

题目大意

有一颗依赖关系构成的一颗树,有两个操作

  1. install ,把从 x 到根节点这一条链全都改为 1
  2. uninstall ,把以 x 为根的子树全都变成 0
    现在求每个操作会改变多少节点的值

题解

标准树剖,但是细节很多

  1. 懒标记开始为 -1,下传后也要变成 -1
  2. 聪明的做法:先记录操作之前 1 的个数,在查询操作后的个数,然后输出差值

Code

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int n,T,lst[N],nxt[N<<1],to[N<<1],cnt,odd,dfn[N],sz[N],top[N],dep[N],fa[N],son[N],sm[N<<3],tg[N<<3];
inline void Ae(int fr,int go) { to[++cnt]=go,nxt[cnt]=lst[fr],lst[fr]=cnt; }
char opt[15];
void Get(int u,int f) {
	sz[u]=1,dep[u]=dep[fa[u]=f]+1;
	for(int i=lst[u];i;i=nxt[i])
		if(to[i]^f) {
			Get(to[i],u),sz[u]+=sz[to[i]];
			if(sz[to[i]]>sz[son[u]])son[u]=to[i];
		}
}
void Dfs(int u,int nw) {
	top[u]=nw,dfn[u]=++odd;
	if(!son[u])return; Dfs(son[u],nw);
	for(int i=lst[u];i;i=nxt[i])
	if(to[i]^fa[u] && to[i]^son[u])Dfs(to[i],to[i]);
}
inline void Up(int rt) { sm[rt]=sm[rt<<1]+sm[rt<<1|1]; }
void Build(int l,int r,int rt) {
	if(l==r)return; register int mid=l+r>>1;
	Build(l,mid,rt<<1),Build(mid+1,r,rt<<1|1);
}
inline void Down(int rt,int len) {
	sm[rt<<1]=(len+1>>1)*tg[rt],tg[rt<<1]=tg[rt];
	sm[rt<<1|1]=(len>>1)*tg[rt],tg[rt<<1|1]=tg[rt],tg[rt]=-1;
}
void Modify(int ql,int qr,int vl,int l,int r,int rt) {
	if(ql<=l && r<=qr) { sm[rt]=vl*(r-l+1),tg[rt]=vl; return; }
	register int mid=l+r>>1; if(tg[rt]!=-1)Down(rt,r-l+1);
	if(ql<=mid)Modify(ql,qr,vl,l,mid,rt<<1);
	if(qr>mid)Modify(ql,qr,vl,mid+1,r,rt<<1|1); Up(rt);
}
inline void Change(int x) {
	for(;top[x]^top[1];x=fa[top[x]])
		Modify(dfn[top[x]],dfn[x],1,1,n,1);
	Modify(1,dfn[x],1,1,n,1);
}
int main() {
	freopen("manager.in","r",stdin);
	freopen("manager.out","w",stdout);
	scanf("%d",&n);
	for(int i=2,u;i<=n;i++) {
		scanf("%d",&u),++u;
		Ae(i,u),Ae(u,i);
	}
	Get(1,0),Dfs(1,1),Build(1,n,1);
	scanf("%d",&T);
	for(int u,pr,ft;T--;) {
		scanf("%s%d",opt,&u),++u;
		pr=sm[1];
		if(opt[0]=='i')Change(u);
		else if(opt[0]=='u')Modify(dfn[u],dfn[u]+sz[u]-1,0,1,n,1);
		ft=sm[1];
		printf("%d
",abs(pr-ft));
	}
}
原文地址:https://www.cnblogs.com/KonjakLAF/p/14332248.html