【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说明:

Pic

一开始所有的软件包都处于未安装状态。
安装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 }
 
    

 

 

转载于:https://www.cnblogs.com/pantakill/p/6622335.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值