【NOI2015】软件包管理器
P2106 - 【NOI2015】软件包管理器
Description
你决定设计你自己的软件包管理器。不可避免的,你要解决软件包之间的依赖关系。如果A依赖B,那么安装A之前需安装B,卸载B之前须卸载A。0号软件包不依赖任何软件包。依赖关系不存在环(包括自环)。
你的任务是,求出每次安装、删除操作会改变多少个包的状态。
安装一个已安装的软件包,或者卸载一个未安装的软件包,都不会改变任何软件包的安装状态,即在此情况下,改变安装状态的软件包数为0
每次操作不仅需要计算安装软件包数,还作为操作影响后来的安装/删除
Input
第一行一个整数n,表示软件包的总数。
随后n-1个整数a1,a2,...an-1,表示第i个软件包依赖第ai个软件包
接下来一行一个整数q,表示询问数
之后q行,每行一个询问,询问分为两种
install x:表示安装x
uninstall x:表示卸载x
Output
q行,每行一个整数,为第i步操作改变安装状态的软件包数
Sample Input
样例输入1:
7
0 0 0 1 1 5
5
install 5
install 6
uninstall 1
install 4
uninstall 0
样例输入2:
10
0 1 2 1 3 0 0 3 2
10
install 0
install 3
uninstall 2
install 7
install 5
install 9
uninstall 9
install 4
install 1
install 9
Sample Output
样例输出1:
3
1
3
2
3
样例输出2:
1
3
2
1
3
1
1
1
0
1
Hint
样例输入1说明:
一开始所有的软件包都处于未安装状态。
安装5号软件包,需安装0,1,5三个软件包
之后安装6号软件包,只需安装6号软件包。此时安装了0,1,5,6四个软件包。
卸载1号软件包需要卸载1,5,6三个软件包,此时只有0号软件包还处于安装状态
之后安装4号软件包,需安装1,4两个软件包。此时0,1,4处于安装状态
最后,卸载0号软件包会卸载所有的软件包
数据提示:
1,2:n=5000 q=5000
3,4:n=100000 q=100000 没有卸载操作
5,6,7,8 n=100000,q=100000 依赖关系和操作随机
9-20 n=100000,q=100000 不随机
先树链剖分,用线段树维护一下,线段树中初始值为1,表示这个软件包还没有安装。
对于每个安装操作,查询这个点到根的权值和即可,并且要把查询的这一段都修改为0,表示已经安装。
对于每个卸载操作,要查询以这个点为根的子树中有多少个点已经安装。
这里需要在第二遍DFS的时候把回溯到这个点的dfn记录下来,
因为某个点的dfn和回溯到这个点的dfn在线段树中对应的那个区间就刚好是以这个点为根的子树。
这样就可以直接查询了。查询后把这个区间修改为1。
关于lazy数组要注意一下,lazy[i]=0就代表这个点对应的区间都是安装了的,
lazy[i]=1就代表这个点对应的区间都是没有安装的。
所以lazy的初值不能赋为1也不能赋为0,在下放时,lazy[i]为初值时是不要下放的。
这里卡了我蛮久。
1 #include<set> 2 #include<map> 3 #include<queue> 4 #include<stack> 5 #include<ctime> 6 #include<cmath> 7 #include<string> 8 #include<vector> 9 #include<cstdio> 10 #include<cstdlib> 11 #include<cstring> 12 #include<iostream> 13 #include<algorithm> 14 #define maxn 100010 15 #define ls o*2 16 #define rs o*2+1 17 #define mi int mid=(l+r)>>1 18 using namespace std; 19 struct data{ 20 int nex,to; 21 }e[maxn*2]; 22 int head[maxn],edge=0; 23 int dfn1[maxn],dfn2[maxn],size[maxn],top[maxn],son[maxn],dad[maxn],deep[maxn],b[maxn*4],lazy[maxn*4]; 24 int size1[maxn*4],n; 25 char s[12]; 26 void add(int from,int to){ 27 e[++edge].nex=head[from]; 28 e[edge].to=to; 29 head[from]=edge; 30 } 31 void build(int o,int l,int r){ 32 size1[o]=r-l+1; 33 if(l==r){b[o]=1;return;} 34 mi; 35 build(ls,l,mid);build(rs,mid+1,r); 36 b[o]=b[ls]+b[rs]; 37 } 38 void down(int o){ 39 if(lazy[o]==-1) return; 40 b[ls]=size1[ls]*lazy[o]; 41 b[rs]=size1[rs]*lazy[o]; 42 lazy[ls]=lazy[o];lazy[rs]=lazy[o]; 43 lazy[o]=-1; 44 } 45 void dfs1(int x,int fa){ 46 size[x]++; 47 for(int i=head[x];i;i=e[i].nex){ 48 int u=e[i].to; 49 if(u==fa) continue; 50 dad[u]=x; 51 deep[u]=deep[x]+1; 52 dfs1(u,x); 53 size[x]+=size[u]; 54 if(size[son[x]]<size[u]) son[x]=u; 55 } 56 } 57 int de=0; 58 void dfs2(int x,int fa){ 59 ++de; 60 dfn1[x]=de; 61 if(son[x]) top[son[x]]=top[x],dfs2(son[x],x); 62 for(int i=head[x];i;i=e[i].nex){ 63 int u=e[i].to; 64 if(u==fa || u==son[x])continue; 65 top[u]=u; 66 dfs2(u,x); 67 } 68 dfn2[x]=de; 69 } 70 int find(int o,int l,int r,int u,int v){ 71 if(l!=r) down(o); 72 if(l>=u && r<=v) return b[o]; 73 if(l>v || r<u) return 0; 74 mi; 75 if(v<=mid) return find(ls,l,mid,u,v); 76 else if(u>mid) return find(rs,mid+1,r,u,v); 77 else return find(ls,l,mid,u,mid)+find(rs,mid+1,r,mid+1,v); 78 } 79 void change(int o,int l,int r,int u,int v,int w){ 80 if(l!=r) down(o); 81 if(l>=u && r<=v){ 82 b[o]=w*size1[o]; 83 lazy[o]=w; 84 return; 85 } 86 if(l>v || r<u) return; 87 mi; 88 if(v<=mid) change(ls,l,mid,u,v,w); 89 else if(u>mid) change(rs,mid+1,r,u,v,w); 90 else change(ls,l,mid,u,mid,w),change(rs,mid+1,r,mid+1,v,w); 91 b[o]=b[ls]+b[rs]; 92 } 93 void lca(int x,int y){ 94 int sum=0; 95 while(top[x]!=top[y]){ 96 if(deep[top[x]]>deep[top[y]]) sum+=find(1,1,n,dfn1[top[x]],dfn1[x]), 97 change(1,1,n,dfn1[top[x]],dfn1[x],0),x=dad[top[x]]; 98 else sum+=find(1,1,n,dfn1[top[y]],dfn1[y]),change(1,1,n,dfn1[top[y]],dfn1[y],0),y=dad[top[y]]; 99 } 100 if(deep[x]>deep[y]) swap(x,y); 101 sum+=find(1,1,n,dfn1[x],dfn1[y]);change(1,1,n,dfn1[x],dfn1[y],0); 102 printf("%d\n",sum); 103 } 104 int main() 105 { 106 freopen("!.in","r",stdin); 107 freopen("!.out","w",stdout); 108 int x; 109 scanf("%d",&n); 110 for(int i=2;i<=n;i++) 111 scanf("%d",&x),add(x+1,i),add(i,x+1); 112 for(int i=0;i<=4*n;i++) lazy[i]=-1; 113 top[1]=1,dad[1]=1; 114 dfs1(1,0);dfs2(1,0);build(1,1,n); 115 int qes;scanf("%d",&qes); 116 for(int i=1;i<=qes;i++){ 117 scanf("%s%d",s,&x); 118 x++; 119 if(s[0]=='i') lca(1,x); 120 if(s[0]=='u'){ 121 printf("%d\n",size[x]-find(1,1,n,dfn1[x],dfn2[x])); 122 change(1,1,n,dfn1[x],dfn2[x],1); 123 } 124 } 125 }