[Bzoj4196] [NOI2015] 软件包管理器 [树链剖分,线段树]

题解摘要:树链剖分后用线段树区间查询修改,对于安装软件,将改点到根的路径全部变为1,对于卸载软件,将子树清空。注意边界,编号是从0开始的,容易漏掉树根。

第一次写树剖~

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <cstdio>
  4 #include <cstdlib>
  5 #include <cstring>
  6 #include <cmath>
  7 #include <ctime>
  8 
  9 using namespace std;
 10 
 11 struct Edge
 12 {
 13     int    to,next;
 14 }e[210000];
 15 
 16 int    ind,n,Pre[210000],f[810000],Sum[810000],Out_dfn[210000];
 17 int    p[210000],cnt,hv[210000],Head[210000],Dfn[210000];
 18 
 19 void    Add_edge(const int & x,const int & y)
 20 {
 21     e[++cnt].to=y;
 22     e[cnt].next=p[x];
 23     p[x]=cnt;
 24     return ;
 25 }
 26 
 27 int    Init_Dfs(const int& S)
 28 {
 29     int    num=1,i,Max_=0;
 30     for(i=p[S];i;i=e[i].next)
 31     {
 32         int temp=Init_Dfs(e[i].to);
 33         if(temp>Max_)Max_=temp,hv[S]=e[i].to;
 34         num+=temp;
 35     }
 36     return num;
 37 }
 38 
 39 void    Dfs(const int& S,const int& fa)
 40 {
 41     int    i;
 42     if(!Head[S])Head[S]=Head[fa];Dfn[S]=++ind;
 43     
 44     if(hv[S])Dfs(hv[S],S);
 45     for(i=p[S];i;i=e[i].next)
 46     {
 47         if(e[i].to!=hv[S])
 48         {
 49             Head[e[i].to]=e[i].to;
 50             Pre[e[i].to]=S;
 51             Dfs(e[i].to,S);
 52         }
 53     }
 54     Out_dfn[S]=ind;
 55     return ;
 56 }
 57 
 58 inline void    push_down(const int & num,const int & l,const int & r)
 59 {
 60     if(f[num])
 61     {
 62         if(l!=r)
 63         {
 64             f[num<<1]=f[num<<1|1]=f[num];
 65         }
 66         if(f[num]==1)Sum[num]=r-l+1;
 67         if(f[num]==-1)Sum[num]=0;
 68         f[num]=0;
 69     }
 70     return ;
 71 }
 72 
 73 void    push_up(const int & num,const int & l,const int & r)
 74 {
 75     if(l!=r)
 76     {
 77         int    mid=l+((r-l)>>1);
 78         push_down(num<<1,l,mid);
 79         push_down(num<<1|1,mid+1,r);
 80         Sum[num]=Sum[num<<1]+Sum[num<<1|1];
 81     }
 82     return ;
 83 }
 84 
 85 void    Change(const int & l,const int & r,const int & num,
 86         const int & s,const int & t,const int &d)
 87 {
 88     if(s<=l && r<=t)
 89     {
 90         f[num]=d;
 91         push_down(num,l,r);
 92         return ;
 93     }
 94     int    mid=l+((r-l)>>1);
 95     push_down(num,l,r);
 96     if(s<=mid)Change(l,mid,num<<1,s,t,d);
 97     if(t>mid) Change(mid+1,r,num<<1|1,s,t,d);
 98     push_up(num,l,r);
 99     return ;
100 }
101 
102 int    Query(const int & l,const int & r,const int & num,
103         const int & s,const int & t)
104 {
105     if(s<=l && r<=t)
106     {
107         push_down(num,l,r);
108         return Sum[num];
109     }
110 
111     int    mid=l+((r-l)>>1),temp=0;
112     push_down(num,l,r);
113     if(s<=mid)temp+=Query(l,mid,num<<1,s,t);
114     if(t>mid) temp+=Query(mid+1,r,num<<1|1,s,t);
115     push_up(num,l,r);
116     return temp;
117 }
118 
119 int    Get_sum_install(const int& S)
120 {
121     int    x=S,temp=0,sum=0;
122     
123     while(x)
124     {
125         sum+=Query(1,n,1,Dfn[Head[x]],Dfn[x]);
126         Change(1,n,1,Dfn[Head[x]],Dfn[x],1);
127         temp+=Dfn[x]-Dfn[Head[x]]+1;
128         x=Pre[Head[x]];
129     }
130     
131     return temp-sum;
132 }
133 
134 int    Get_sum_remove(const int & S)
135 {
136     int    x=S,sum=0;
137 
138     sum=Query(1,n,1,Dfn[x],Out_dfn[x]);
139     Change(1,n,1,Dfn[x],Out_dfn[x],-1);
140 
141     return sum;
142 }
143     
144 int main()
145 {
146 
147     int    i,x,q;
148     char    op[15];
149 
150     scanf("%d",&n);
151     for(i=2;i<=n;++i)
152     {
153         scanf("%d",&x);x++;
154         Add_edge(x,i);
155     }
156 
157     Init_Dfs(1);
158 
159     Head[1]=1;
160     Dfs(1,1);
161     scanf("%d",&q);
162     for(i=1;i<=q;++i)
163     {
164         scanf("%s%d",op,&x);x++;
165         if(op[0]=='i')
166             printf("%d\n",Get_sum_install(x));
167         else
168             printf("%d\n",Get_sum_remove(x));
169     }
170 
171     return 0;
172 }
View Code

不知道为什么,BZOJ TLE了,但是UOJ AC(求大神指教)??

转载于:https://www.cnblogs.com/Gster/p/4977886.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值