P2146 [NOI2015] 软件包管理器
题意:
如果软件包 a 依赖软件包 b,那么安装软件包 a 以前,必须先安装软件包 b。同时,如果想要卸载软件包 b,则必须卸载软件包 a。
软件包之间存在依赖关系,除了0号软件包以外,其他软件包都会依赖一个且仅一个软件包。不会存在环的情况
现在对某个软件包进行安装和卸载,问这个操作实际上会改变多少个软件包的安装状态
题解:
本质就两个操作,安装是询问节点x到根节点的操作,卸载是查询x的子树的操作。但是题目中问的是每一步操作会改变多少状态,所以我们需要记录上一次的状态,然后操作完后得到现在的状态,差的绝对值就是本次操作的答案
代码:
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define full(a,b) memset(a,b,sizeof a)
#define N 100005
int n,q;
int head[N],ecnt,nxt[N],to[N];
int dad[N],son[N],dep[N],size[N];
int top[N],id[N],rev[N];
int last,s[4*N],lazy[4*N];
void init()//初始化
{full(head,-1);full(lazy,-1);
}
int read()//快读
{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') f=ch=='-'?-1:1,ch=getchar();while(ch>='0'&&ch<='9') x=10*x+ch-'0',ch=getchar();return x*f;
}
void add(int u,int v)//增加结点
{to[++ecnt]=v;nxt[ecnt]=head[u];head[u]=ecnt;
}
void pre(int u,int fa)//求深度,子结点等
{dep[u]=dep[fa]+1;dad[u]=fa;size[u]=1;for(int i=head[u]; i!=-1; i=nxt[i]){int v=to[i];if(v==fa) continue;pre(v,u);size[u]+=size[v];if(size[v]>size[son[u]]) son[u]=v;}
}
void dfsx(int u)//求链
{int v=son[u];if(v){id[v]=++id[0];rev[id[0]]=v;top[v]=top[u];dfsx(v);}for(int i=head[u]; i!=-1; i=nxt[i]){v=to[i];if(top[v]) continue;id[v]=++id[0];rev[id[0]]=v;top[v]=v;dfsx(v);}
}
void pushdown(int k,int l,int r)//传递lazy标记
{if(lazy[k]==-1) return;int mid=(l+r)>>1;lazy[2*k]=lazy[2*k+1]=lazy[k];s[2*k]=(mid-l+1)*lazy[k];s[2*k+1]=(r-mid)*lazy[k];lazy[k]=-1;
}
void update(int k,int l,int r,int x,int y,int v)//区间修改模板
{if(x>r||y<l) return;if(x<=l&&r<=y){s[k]=v*(r-l+1);lazy[k]=v;return;}int mid=(l+r)>>1;pushdown(k,l,r);update(k*2,l,mid,x,y,v);update(k*2+1,mid+1,r,x,y,v);s[k]=s[2*k]+s[2*k+1];
}
void query(int u,int v)//询问u->v的路径
{int fu=top[u],fv=top[v];while(fu!=fv){if(dep[fu]<dep[fv]) swap(u,v),swap(fu,fv);update(1,1,n,id[fu],id[u],1);u=dad[fu];fu=top[u];}if(dep[u]>dep[v]) swap(u,v);update(1,1,n,id[u],id[v],1);
}
int main()
{init();n=read();for(int i=2; i<=n; i++){int x=read()+1;//下标从1开始 add(x,i);}pre(1,0);id[1]=++id[0];rev[1]=1;top[1]=1;dfsx(1);///造链 q=read();for(int i=1; i<=q; i++){char flag[15];scanf("\n%s",flag);int x=read()+1;//下标从1开始 if(flag[0]=='i') query(1,x);//询问x到根节点 else update(1,1,n,id[x],id[x]+size[x]-1,0);//删除子树 printf("%d\n",abs(last-s[1]));//输出差的绝对值 last=s[1];//更新结点数 }return 0;
}
重温一遍,每次修改完值与上一次进行比较
#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn=200005;
int n,k=0,x,head[maxn],q,deep[maxn],father[maxn],size[maxn];
int tid[maxn],top[maxn],son[maxn],tidnum=0,pos[maxn];char s[15];
struct node
{int to,next;
} edge[maxn<<1];
struct Node
{int left,right,flag,sum;
} tree[maxn<<2];
void add(int u,int v)
{edge[++k].to=v;edge[k].next=head[u];head[u]=k;
}
int read()
{int x=0;char ch=getchar();while(ch<48||ch>57) ch=getchar();while(ch>=48&&ch<=57) x=x*10+ch-48,ch=getchar();return x;
}
void dfs1(int x,int fa,int depth)
{size[x]=1;father[x]=fa;deep[x]=depth;for(int i=head[x];i;i=edge[i].next){if(edge[i].to==fa) continue;dfs1(edge[i].to,x,depth+1);size[x]+=size[edge[i].to];if(!son[x]||size[edge[i].to]>size[son[x]]) son[x]=edge[i].to;}
}
void dfs2(int x,int tp)
{tid[x]=++tidnum;pos[tid[x]]=x;top[x]=tp;if(!son[x]) return;dfs2(son[x],tp);for(int i=head[x];i;i=edge[i].next){if(edge[i].to!=son[x]&&edge[i].to!=father[x])dfs2(edge[i].to,edge[i].to);}
}
void build(int id,int l,int r)
{tree[id].left=l;tree[id].right=r;tree[id].sum=0;tree[id].flag=-1;if(l==r) return;int mid=(l+r)>>1;build(id<<1,l,mid);build(id<<1|1,mid+1,r);return;
}
void downdata(int id)
{tree[id<<1].sum=(tree[id<<1].right-tree[id<<1].left+1)*tree[id].flag;tree[id<<1|1].sum=(tree[id<<1|1].right-tree[id<<1|1].left+1)*tree[id].flag;tree[id<<1].flag=tree[id<<1|1].flag=tree[id].flag;tree[id].flag=-1;
}
int get(int id,int l,int r)
{if(tree[id].right<l||tree[id].left>r) return 0;if(tree[id].right<=r&&tree[id].left>=l) return tree[id].sum;if(tree[id].flag!=-1) downdata(id);return get(id<<1,l,r)+get(id<<1|1,l,r);
}
void update(int id,int l,int r,int val)
{if(tree[id].right<l||tree[id].left>r) return;if(tree[id].right<=r&&tree[id].left>=l){tree[id].sum=(tree[id].right-tree[id].left+1)*val;tree[id].flag=val;return;}if(tree[id].flag!=-1) downdata(id);update(id<<1,l,r,val);update(id<<1|1,l,r,val);tree[id].sum=tree[id<<1].sum+tree[id<<1|1].sum;return;
}
void change(int u,int v,int val)
{while(top[u]!=top[v]){if(deep[top[u]]<deep[top[v]]) std::swap(u,v);update(1,tid[top[u]],tid[u],val);u=father[top[u]];}if(deep[u]>deep[v]) std::swap(u,v);update(1,tid[u],tid[v],val);return;
}
int main()
{n=read();for(int i=2;i<=n;i++){x=read();x++;add(x,i);}dfs1(1,1,1);dfs2(1,1);q=read();build(1,1,tidnum);for(int i=1;i<=q;i++){scanf("%s",s);x=read();x++;int t1=tree[1].sum;if(s[0]=='i'){change(1,x,1);//1到x权值变成1 int t2=tree[1].sum;printf("%d\n",abs(t2-t1));}if(s[0]=='u'){update(1,tid[x],tid[x]+size[x]-1,0);//1到x权值变成0 int t2=tree[1].sum;printf("%d\n",abs(t1-t2));}}return 0;
}