题目
题解
这题可以说是链剖的裸体了。并且运用了差分的思想
首先软件存在权值为1,不存在权值为0.
- install操作 查询x到根节点的路径权值和,然后与x的deep做差,之后把点的权值都修改成1
- uninstall操作 查询以x为根的子树的权值和。然后删除
一个小技巧:注意把点权修改成1而不是累加,可以
sum[rt]=(r-l+1)*C;//这里就不能累加了
add[rt]=(C==1)?1:-1; return;
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<iostream>
const int maxn=100007;
int n,m,a[maxn],head[maxn],num_edge,sum[maxn<<2],add[maxn<<2];
bool b[maxn];//i软件现在是否存在
struct Edge {int to,next;}edge[maxn<<1];
int dfn[maxn],idfn[maxn],deep[maxn],top[maxn],son[maxn],fa[maxn],tot[maxn];
void swap(int &a,int &b) {int t=a; a=b; b=t;}
void add_edge(int from,int to)
{
edge[++num_edge].next=head[from];
edge[num_edge].to=to;
head[from]=num_edge;
}
void dfs1(int x,int father,int depth)
{
fa[x]=father;
deep[x]=depth;
tot[x]=1;
int maxnow=-1;
for (int i=head[x]; i!=0; i=edge[i].next)
{
int to=edge[i].to;
if (father!=to)
{
dfs1(to,x,depth+1);
tot[x]+=tot[to];
if (tot[to]>maxnow)
{
maxnow=tot[to];
son[x]=to;
}
}
}
}
int cnt;
void dfs2(int x,int tp)
{
dfn[x]=++cnt;
top[x]=tp;
if (!son[x]) return;
dfs2(son[x],tp);
for (int i=head[x]; i!=0; i=edge[i].next)
{
int to=edge[i].to;
if (to!=fa[x] && to!=son[x])
dfs2(to,to);
}
}
void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(int rt,int ln,int rn)
{
if (add[rt])
{
int k=(add[rt]==1)?1:0;//只有add为1的时候说明只被标记过一次
add[rt<<1]=add[rt<<1|1]=add[rt];
sum[rt<<1]=ln*k;
sum[rt<<1|1]=rn*k;
add[rt]=0;
}
}
int ques(int L,int R,int l,int r,int rt)
{
if (L<=l && r<=R) return sum[rt];
int mid=(l+r)>>1;
int ans=0;
pushdown(rt,mid-l+1,r-mid);
if (L<=mid) ans+=ques(L,R,l,mid,rt<<1);
if (R>mid) ans+=ques(L,R,mid+1,r,rt<<1|1);
return ans;
}
void change(int L,int R,int C,int l,int r,int rt)
{
if (L<=l && r<=R)
{
sum[rt]=(r-l+1)*C;//这里就不能累加了
add[rt]=(C==1)?1:-1; return;
}
int mid=(l+r)>>1;
pushdown(rt,mid-l+1,r-mid);
if (L<=mid) change(L,R,C,l,mid,rt<<1);
if (R>mid) change(L,R,C,mid+1,r,rt<<1|1);
pushup(rt);
}
void Treechange(int x)//x节点到根都变成1
{
while (top[x]!=0)//每次更新一条重链,一直到根节点
{
change(dfn[top[x]],dfn[x],1,1,n,1);
x=fa[top[x]];
}
}
int Treeques(int x)
{
int ans=0;
while (top[x]!=0)
{
ans+=ques(dfn[top[x]],dfn[x],1,n,1);
x=fa[top[x]];
}
return ans;
}
int main()
{
freopen("manager.in","r",stdin);
freopen("manager.out","w",stdout);
scanf("%d",&n);
for (int i=1; i<=n-1; i++)
{
int x;
scanf("%d",&x);
add_edge(x+1,i+1); add_edge(i+1,x+1);
}
dfs1(1,0,1);
dfs2(1,1);
scanf("%d",&m);
for (int i=1; i<=m; i++)
{
char s[20]; int x;
scanf("%s",s); scanf("%d",&x); x++;
if (s[0]=='i')
{
printf("%d\n",deep[x]-Treeques(x));
Treechange(x);
}
else
{
int ans=ques(dfn[x],dfn[x]+tot[x]-1,1,n,1);
printf("%d\n",ans);
change(dfn[x],dfn[x]+tot[x]-1,0,1,n,1);
}
}
return 0;
}
总结
链剖还是打一遍错一遍,要理解算法的本质而不是背诵代码