noi2015软件包管理器

【题目描述】

你决定设计你自己的软件包管理器。不可避免的,你要解决软件包之间的依赖关系。如果A依赖B,那么安装A之前需安装B,卸载B之前须卸载A。0号软件包不依赖任何软件包。依赖关系不存在环(包括自环)。

你的任务是,求出每次安装、删除操作会改变多少个包的状态。

安装一个已安装的软件包,或者卸载一个未安装的软件包,都不会改变任何软件包的安装状态,即在此情况下,改变安装状态的软件包数为0

每次操作不仅需要计算安装软件包数,还作为操作影响后来的安装/删除

【输入格式】

第一行一个整数n,表示软件包的总数。

随后n-1个整数 a1,a2,...an1 ,表示第i个软件包依赖第 ai 个软件包

接下来一行一个整数q,表示询问数

之后q行,每行一个询问,询问分为两种

install xx

uninstall xx

【输出格式】

q行,每行一个整数,为第i步操作改变安装状态的软件包数

【样例输入1】

7

0 0 0 1 1 5

5

install 5

install 6

uninstall 1

install 4

uninstall 0

【样例输出1】

3

1

3

2

3

【样例说明1】:

一开始所有的软件包都处于未安装状态。

安装5号软件包,需安装0,1,5三个软件包

之后安装6号软件包,只需安装6号软件包。此时安装了0,1,5,6四个软件包。

卸载1号软件包需要卸载1,5,6三个软件包,此时只有0号软件包还处于安装状态

之后安装4号软件包,需安装1,4两个软件包。此时0,1,4处于安装状态

最后,卸载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

【样例输出2】

1

3

2

1

3

1

1

1

0

1

【提示】

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 不随机

【来源】

NOI2015Day1T2

对于题面的描述的,我们很容易想到它是棵树,并且节点又是1e+5,我们选择用树剖+线段树;

我们维护线段树上每一个点的状态(安装或未安装,安装用1来表示,未安装用-1来表示)和当前节点已被覆盖的点数,未被覆盖的点数可以也维护,也可以用区间长减去已被覆盖节点数,当一个线段树节点被打上安装或未安装标记时,就将答案加上已被覆盖的点数或未被覆盖点数并更新其值(一个为0,另一个为区间长),在拿它来更新父亲节点

所维护的信息,最后输出答案就行。。

代码如下:


  
  
  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <string>
  5. #include <algorithm>
  6. using namespace std;
  7. const int MAX=100000+10;
  8. int fa[MAX];
  9. int dep[MAX];
  10. int son[MAX]={0};
  11. int top[MAX];
  12. int size[MAX];
  13. int tid[MAX];
  14. int head[MAX]={0};
  15. int to[MAX<<1];
  16. int next[MAX<<1]={0};
  17. int edge=1,tim=0;
  18. int n;
  19. inline void dfs1(int x,int p,int d){
  20. fa[x]=p;
  21. dep[x]=d;
  22. size[x]=1;
  23. for(int i=head[x];i;i=next[i]){
  24. int u=to[i];
  25. if(u!=p){
  26. dfs1(u,x,d+1);
  27. size[x]+=size[u];
  28. if(size[u]>size[son[x]]||!son[x])
  29. son[x]=u;
  30. }
  31. }
  32. }
  33. inline void dfs2(int x,int p){
  34. tid[x]=++tim;
  35. top[x]=p;
  36. if(!son[x])
  37. return ;
  38. dfs2(son[x],p);
  39. for(int i=head[x];i;i=next[i]){
  40. int u=to[i];
  41. if(u!=fa[x]&&u!=son[x])
  42. dfs2(u,u);
  43. }
  44. }
  45. #define isnum (c>='0'&&c<='9')
  46. inline void read(int& x){
  47. x=0;
  48. char c=getchar();
  49. while(!isnum)
  50. c=getchar();
  51. while(isnum){
  52. x=(x<<3)+(x<<1)+c-'0';
  53. c=getchar();
  54. }
  55. }
  56. inline void addedge(int x,int y){
  57. to[edge]=y,next[edge]=head[x],head[x]=edge++;
  58. to[edge]=x,next[edge]=head[y],head[y]=edge++;
  59. }
  60. int isum[MAX<<2]={0},usum[MAX<<2];
  61. int ins[MAX<<2]={0};
  62. int ans;
  63. int l,r;
  64. #define lson o<<1,L,mid
  65. #define rson o<<1|1,mid+1,R
  66. inline void pushup(int o){
  67. isum[o]=isum[o<<1]+isum[o<<1|1];
  68. usum[o]=usum[o<<1]+usum[o<<1|1];
  69. }
  70. inline void pushdown(int o,int L,int R){
  71. int mid=(L+R)>>1;
  72. if(ins[o]==1){
  73. isum[o<<1]=(mid-L+1);
  74. usum[o<<1]=0;
  75. isum[o<<1|1]=R-mid;
  76. usum[o<<1|1]=0;
  77. ins[o<<1]=ins[o];
  78. ins[o<<1|1]=ins[o];
  79. ins[o]=0;
  80. }
  81. else {
  82. isum[o<<1]=0;
  83. usum[o<<1]=mid-L+1;
  84. isum[o<<1|1]=0;
  85. usum[o<<1|1]=R-mid;
  86. ins[o<<1]=ins[o];
  87. ins[o<<1|1]=ins[o];
  88. ins[o]=0;
  89. }
  90. }
  91. inline void build(int o,int L,int R){
  92. usum[o]=(R-L+1);
  93. if(L==R){
  94. return ;
  95. }
  96. int mid=(L+R)>>1;
  97. build(lson);
  98. build(rson);
  99. pushup(o);
  100. }
  101. inline void query1(int o,int L,int R){
  102. if(L>=l&&R<=r){
  103. ins[o]=1;
  104. ans+=usum[o];
  105. usum[o]=0;
  106. isum[o]=(R-L+1);
  107. return ;
  108. }
  109. else if(L!=R){
  110. int mid=(L+R)>>1;
  111. if(ins[o]!=0)
  112. pushdown(o,L,R);
  113. if(mid>=l)
  114. query1(lson);
  115. if(mid<r)
  116. query1(rson);
  117. pushup(o);
  118. }
  119. }
  120. inline void query2(int o,int L,int R){
  121. if(L>=l&&R<=r){
  122. ins[o]=-1;
  123. ans+=isum[o];
  124. isum[o]=0;
  125. usum[o]=(R-L+1);
  126. return ;
  127. }
  128. else if(L!=R){
  129. if(ins[o]!=0)
  130. pushdown(o,L,R);
  131. int mid=(L+R)>>1;
  132. if(mid>=l)
  133. query2(lson);
  134. if(mid<r)
  135. query2(rson);
  136. pushup(o);
  137. }
  138. }
  139. inline void Query1(int x,int y){
  140. ans=0;
  141. while(top[x]!=top[y]){
  142. if(dep[top[x]]<dep[top[y]])
  143. swap(x,y);
  144. l=tid[top[x]];
  145. r=tid[x];
  146. query1(1,1,n);
  147. x=fa[top[x]];
  148. }
  149. if(dep[x]>dep[y])
  150. swap(x,y);
  151. l=tid[x],r=tid[y];
  152. query1(1,1,n);
  153. }
  154. inline void Query2(int x){
  155. ans=0;
  156. l=tid[x],r=tid[x]+size[x]-1;
  157. query2(1,1,n);
  158. }
  159. int main(){
  160. freopen("manager.in","r",stdin);
  161. freopen("manager.out","w",stdout);
  162. read(n);
  163. int x;
  164. for(int i=2;i<=n;i++){
  165. read(x);
  166. addedge(i,x+1);
  167. }
  168. int m;
  169. read(m);
  170. dfs1(1,1,1);
  171. dfs2(1,1);
  172. build(1,1,n);
  173. string s;
  174. for(int i=1;i<=m;i++){
  175. cin>>s;
  176. read(x);
  177. if(s[0]=='i'){
  178. Query1(1,x+1);
  179. printf("%d\n",ans);
  180. }
  181. else {
  182. Query2(x+1);
  183. printf("%d\n",ans);
  184. }
  185. }
  186. return 0;
  187. }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值