P2146 [NOI2015]软件包管理器

https://www.luogu.com.cn/problem/P2146

题意:给出一棵树,然后有两种操作,安装与卸载;

安装就是,想要安装这个软件,就得安装这个软件之前的一个软件,即:他的父亲,他的父亲的父亲....

卸载就是,想要卸载这个软件,就得把这个软件的儿子都卸载了才能卸载;

那么他具体问的就是,每次安装(卸载)的操作,需要安装(卸载)多少个软件;

所以我们只需要处理处每一个安装包的状态,然后通过状态来计数即可;

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int maxn=1e5+10;
  4 const int mod=1e9+7;
  5 struct node
  6 {
  7     int v,nxt;
  8 }G[maxn*2]; int head[maxn]; int num;
  9 int w[maxn],wt[maxn];
 10 //链式前向星数组,w[]、wt[]初始点权数组
 11 int son[maxn],id[maxn],fa[maxn],cnt,dep[maxn],siz[maxn],top[maxn];
 12 void init()
 13 {
 14     memset(head,-1,sizeof(head));
 15     num=-1;
 16 }
 17 struct tre
 18 {
 19     int l,r,lazy,sum;
 20 }tree[maxn<<2];
 21 void add(int u,int v)
 22 {
 23     G[++num].v=v;G[num].nxt=head[u];head[u]=num;
 24     G[++num].v=u;G[num].nxt=head[v];head[v]=num;
 25 }
 26 
 27 void build(int l,int r,int root){
 28     tree[root].l=l;tree[root].r=r;
 29     tree[root].sum=tree[root].lazy=0;
 30     if(l==r){
 31         tree[root].sum=0;
 32         return;
 33     }
 34     int mid=l+r>>1;
 35     build(l,mid,root<<1);
 36     build(mid+1,r,root<<1|1);
 37     tree[root].sum=(tree[root<<1].sum+tree[root<<1|1].sum)%mod;
 38 }
 39 void pushdown(int rt,int lenn){
 40     tree[rt<<1].lazy=tree[rt].lazy;
 41     tree[rt<<1|1].lazy=tree[rt].lazy;
 42     if(tree[rt].lazy==1){
 43         tree[rt<<1].sum=tree[rt].lazy*(lenn-(lenn>>1));
 44         tree[rt<<1|1].sum=tree[rt].lazy*(lenn>>1);
 45     }
 46     else{
 47         tree[rt<<1].sum=tree[rt<<1|1].sum=0;
 48     }
 49     tree[rt].lazy=0;
 50 }
 51 void update(int l,int r,int val,int root){
 52     int L=tree[root].l;int R=tree[root].r;
 53     if(l<=L&&R<=r){
 54         if(val) tree[root].lazy=val;
 55         else tree[root].lazy=-1;
 56         tree[root].sum=val*(R-L+1);
 57     }
 58     else{
 59         if(tree[root].lazy!=0)pushdown(root,R-L+1);
 60         int mid=L+R>>1;
 61         if(l<=mid)update(l,r,val,root<<1);
 62         if(r>mid) update(l,r,val,root<<1|1);
 63         tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum;
 64     }
 65 }
 66 int query(int l,int r,int root,int flag){
 67     int L=tree[root].l;int R=tree[root].r;
 68     if(l<=L&&R<=r){
 69         int tmp=tree[root].sum;
 70         if(flag==0) return R-L+1-tmp;
 71         else return tmp;
 72     }
 73     if(tree[root].lazy)pushdown(root,R-L+1);
 74     int mid=L+R>>1;
 75     int ans=0;
 76     if(l<=mid) ans+=query(l,r,root<<1,flag);
 77     if(r>mid)  ans+=query(l,r,root<<1|1,flag);
 78     return ans;
 79 }
 80 void dfs1(int u,int f,int deep){//x当前节点,f父亲,deep深度
 81     dep[u]=deep;//标记每个点的深度
 82     fa[u]=f;//标记每个点的父亲
 83     siz[u]=1;//标记每个非叶子节点的子树大小
 84     int maxson=-1;//记录重儿子的儿子数
 85     for(int i=head[u];i!=-1;i=G[i].nxt){
 86         int v=G[i].v;
 87         if(v==f)continue;//若为父亲则continue
 88         dfs1(v,u,deep+1);//dfs其儿子
 89         siz[u]+=siz[v];//把它的儿子数加到它身上
 90         if(siz[v]>maxson)son[u]=v,maxson=siz[v];//标记每个非叶子节点的重儿子编号
 91     }
 92 }
 93 
 94 void dfs2(int u,int topf){//x当前节点,topf当前链的最顶端的节点
 95     id[u]=++cnt;//标记每个点的新编号
 96     top[u]=topf;//这个点所在链的顶端
 97     if(!son[u])return;//如果没有儿子则返回
 98     dfs2(son[u],topf);//按先处理重儿子,再处理轻儿子的顺序递归处理
 99     for(int i=head[u];i!=-1;i=G[i].nxt){
100         int v=G[i].v;
101         if(v==fa[u]||v==son[u])continue;
102         dfs2(v,v);//对于每一个轻儿子都有一条从它自己开始的链
103     }
104 }
105 int qRange(int x,int y,int flag){
106     int ans=0;
107     while(top[x]!=top[y]){//当两个点不在同一条链上
108         if(dep[top[x]]<dep[top[y]])swap(x,y);//把x点改为所在链顶端的深度更深的那个点
109         ans+=query(id[top[x]],id[x],1,flag);//ans加上x点到x所在链顶端 这一段区间的点权和
110         x=fa[top[x]];//把x跳到x所在链顶端的那个点的上面一个点
111     }
112     //直到两个点处于一条链上
113     if(dep[x]>dep[y])swap(x,y);//把x点深度更深的那个点
114     ans+=query(id[x],id[y],1,flag);//这时再加上此时两个点的区间和即可
115     return ans;
116 }
117 void updRange(int x,int y,int k){//同上
118     while(top[x]!=top[y]){
119         if(dep[top[x]]<dep[top[y]])swap(x,y);
120         update(id[top[x]],id[x],k,1);
121         x=fa[top[x]];
122     }
123     if(dep[x]>dep[y])swap(x,y);
124     update(id[x],id[y],k,1);
125 }
126 
127 int main()
128 {
129     init();
130     int n;
131     scanf("%d",&n);
132     for(int i=1;i<n;i++){
133         int u,v;
134         v=i+1; scanf("%d",&u);
135         u++;
136         add(u,v);
137     }
138     dfs1(1,0,1);
139     dfs2(1,1);
140     build(1,n,1);
141     int q;
142     scanf("%d",&q);
143     while(q--){
144         string tmp1;
145         int tmp2;
146         cin>>tmp1>>tmp2;
147         tmp2++;
148         if(tmp1[0]=='i'){
149             printf("%d\n",qRange(1,tmp2,0));
150             updRange(1,tmp2,1);
151         }
152         else{
153             printf("%d\n",query(id[tmp2],id[tmp2]+siz[tmp2]-1,1,1));
154             update(id[tmp2],id[tmp2]+siz[tmp2]-1,0,1);
155         }
156     }
157     return 0;
158 }

 

posted @ 2020-02-24 11:04  古比  阅读(157)  评论(0编辑  收藏  举报