Bzoj3779 重组病毒

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 408  Solved: 163
[Submit][Status][Discuss]

Description

黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒。这种病毒的繁殖和变异能力极强。为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒。
实验在一个封闭的局域网内进行。局域网内有n台计算机,编号为1~n。一些计算机之间通过网线直接相连,形成树形的结构。局域网中有一台特殊的计算机,称之为核心计算机。根据一些初步的研究,研究员们拟定了一个一共m步的实验。实验开始之前,核心计算机的编号为1,每台计算机中都有病毒的一个变种,而且每台计算机中的变种都不相同。实验中的每一步会是下面中的一种操作:
1、 RELEASE x
在编号为x的计算机中植入病毒的一个新变种。这个变种在植入之前不存在于局域网中。
2、 RECENTER x
将核心计算机改为编号为x的计算机。但是这个操作会导致原来核心计算机中的病毒产生新变种,并感染过来。换言之,假设操作前的核心计算机编号为y,相当于在操作后附加了一次RELEASE y的操作。
根据研究的结论,在植入一个新变种时,病毒会在局域网中搜索核心计算机的位置,并沿着网络中最短的路径感染过去。
而第一轮实验揭露了一个惊人的真相:病毒的不同变种是互斥的。新变种在感染一台已经被旧变种感染的电脑时,会把旧变种完全销毁之后再感染。但研究员发现了实现过程中的漏洞。如果新变种在感染过程中尚未销毁过这类旧变种,需要先花费1单位时间分析旧变种,才能销毁。如果之前销毁过这类旧变种,就可以认为销毁不花费时间。病毒在两台计算机之间的传播亦可认为不花费时间。
研究员对整个感染过程的耗时特别感兴趣,因为这是消灭病毒的最好时机。于是在m步实验之中,研究员有时还会做出如下的询问:
3、 REQUEST x
询问如果在编号为x的计算机的关键集合中的计算机中植入一个新变种,平均感染时间为多长。编号为y的计算机在编号为x的计算机的关键集合中,当且仅当从y沿网络中的最短路径感染到核心计算机必须经过x。由于有RECENTER操作的存在,这个集合并不一定是始终不变的。
至此,安全机构认为已经不需要实际的实验了,于是他们拜托你编写一个程序,模拟实验的结果,并回答所有的询问。

 

Input

输入的第一行包含两个整数n和m,分别代表局域网中计算机的数量,以及操作和询问的总数。
接下来n-1行,每行包含两个整数x和y,表示局域网中编号为x和y的计算机之间有网线直接相连。
接下来m行,每行包含一个操作或者询问,格式如问题描述中所述。
 

 

Output

对于每个询问,输出一个实数,代表平均感染时间。输出与答案的绝对误差不超过 10^(-6)时才会被视为正确。

 

Sample Input

8 6
1 2
1 3
2 8
3 4
3 5
3 6
4 7
REQUEST 7
RELEASE 3
REQUEST 3
RECENTER 5
RELEASE 2
REQUEST 1

Sample Output

4.0000000000
2.0000000000
1.3333333333

HINT

 

N < = 1 00 000 M < = 1 00 000

 

 

树 LCT+LCA+线段树 脑洞题

初始的时候,每个结点的权值就是它的深度。

观察发现每个结点的权值实际上就是它access的时候向上经过的虚边数量。

于是1操作就是access,路上把LCT结点的原右儿子所在子树权值全部+1,把新右儿子所在子树权值全部-1,这一过程可以用DFS序+线段树维护

2操作就是makeroot,自带一个access操作

3操作换根比较麻烦,实际上只需要记录当前根,每次仍在最初的树上操作,根据原根与现根的位置关系讨论即可。

↑比如说这种情况,要修改的就是除了nowroot所在子树区间以外的左右两段(图中没有左段)区间

  

  1 /*by SilverN*/
  2 #include<algorithm>
  3 #include<iostream>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<cmath>
  7 #include<vector>
  8 #define LL long long
  9 using namespace std;
 10 const int mxn=100010;
 11 int read(){
 12     int x=0,f=1;char ch=getchar();
 13     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 14     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
 15     return x*f;
 16 }
 17 struct edge{
 18     int v,nxt;
 19 }e[mxn<<1];
 20 int hd[mxn],mct=0;
 21 void add_edge(int u,int v){
 22     e[++mct].v=v;e[mct].nxt=hd[u];hd[u]=mct;return;
 23 }
 24 namespace TC{
 25     struct node{
 26         int fa,top,son;
 27         int sz;
 28     }t[mxn];
 29     int dep[mxn],ind[mxn],out[mxn],dtime;
 30     int mp[mxn];
 31     void DFS(int u,int ff){
 32         dep[u]=dep[ff]+1;
 33         t[u].sz++;
 34         for(int i=hd[u],v;i;i=e[i].nxt){
 35             if(e[i].v==ff)continue;
 36             v=e[i].v;
 37             t[v].fa=u;
 38             DFS(v,u);
 39             t[u].sz+=t[v].sz;
 40             if(t[v].sz>t[t[u].son].sz)t[u].son=v;
 41         }
 42         return;
 43     }
 44     void DFS2(int u,int top){
 45         ind[u]=++dtime;
 46         mp[dtime]=u;
 47         t[u].top=top;
 48         if(t[u].son){
 49             DFS2(t[u].son,top);
 50             for(int i=hd[u];i;i=e[i].nxt){
 51                 if(e[i].v==t[u].son || e[i].v==t[u].fa)continue;
 52                 DFS2(e[i].v,e[i].v);
 53             }
 54         }
 55         out[u]=dtime;
 56         return;
 57     }
 58     int LCA(int x,int y){
 59         int last=0;
 60         while(t[x].top!=t[y].top){
 61             if(dep[t[x].top]<dep[t[y].top])swap(x,y);
 62             last=t[x].top;
 63             x=t[t[x].top].fa;
 64         }
 65         if(x==y)return last;
 66             else return t[y].son;
 67     }
 68 }
 69 int n,m,nowroot;
 70 struct SGT{
 71     #define lc rt<<1
 72     #define rc rt<<1|1
 73     struct node{
 74         LL smm,mk,mx;
 75     }t[mxn<<2];
 76     void pushup(int rt){
 77         t[rt].smm=t[lc].smm+t[rc].smm;
 78         return;
 79     }
 80     inline void PD(int l,int r,int rt){
 81         if(t[rt].mk){
 82             t[lc].mk+=t[rt].mk;
 83             t[rc].mk+=t[rt].mk;
 84             int mid=(l+r)>>1;
 85             t[lc].smm+=t[rt].mk*(LL)(mid-l+1);
 86             t[rc].smm+=t[rt].mk*(LL)(r-mid);
 87             t[lc].mx+=t[rt].mk;t[rc].mx+=t[rt].mk;
 88             t[rt].mk=0;
 89         }
 90         return;
 91     }
 92     void Build(int l,int r,int rt){
 93         if(l==r){
 94             t[rt].smm=t[rt].mx=TC::dep[TC::mp[l]];    return;
 95         }
 96         int mid=(l+r)>>1;
 97         Build(l,mid,lc);Build(mid+1,r,rc);
 98         pushup(rt);
 99         return;
100     }
101     void update(int L,int R,int v,int l,int r,int rt){
102         if(L>R)return;
103         if(L<=l && r<=R){
104             t[rt].mk+=v;
105             t[rt].smm+=(LL)v*(LL)(r-l+1);
106             return;
107         }
108         PD(l,r,rt);
109         int mid=(l+r)>>1;
110         if(L<=mid)update(L,R,v,l,mid,lc);
111         if(R>mid)update(L,R,v,mid+1,r,rc);
112         pushup(rt);
113         return;
114     }
115     LL qsum(int L,int R,int l,int r,int rt){
116         if(L>R)return 0;
117         if(L<=l && r<=R){return t[rt].smm;}
118         PD(l,r,rt);
119         LL res=0;
120         int mid=(l+r)>>1;
121         if(L<=mid)res+=qsum(L,R,l,mid,lc);
122         if(R>mid)res+=qsum(L,R,mid+1,r,rc);
123         pushup(rt);
124         return res;
125     }
126     void Q_UPD(int x,int v){
127         using namespace TC;
128         int rt=nowroot;
129         if(rt==x)update(1,n,v,1,n,1);
130         else 
131             if(ind[x]<ind[rt] && out[rt]<=out[x]){//两段区间 
132                 rt=LCA(rt,x);
133                 update(1,ind[rt]-1,v,1,n,1);
134                 update(out[rt]+1,n,v,1,n,1);
135             }
136             else update(ind[x],out[x],v,1,n,1);
137     }
138     double Query(int x){
139         using namespace TC;
140         LL ans=0,sz=0;
141         int rt=nowroot;
142         if(rt==x)ans=qsum(1,n,1,n,1),sz=n;
143         else if(ind[x]<ind[rt] && out[rt]<=out[x]){
144                 rt=LCA(rt,x);
145                 ans+=qsum(1,ind[rt]-1,1,n,1);
146                 ans+=qsum(out[rt]+1,n,1,n,1);
147                 sz=n-(out[rt]-ind[rt]+1);
148             }
149             else{
150                 ans=qsum(ind[x],out[x],1,n,1),sz=out[x]-ind[x]+1;
151             }
152         double res=(double)ans/(double)sz;
153         printf("%.10f\n",res);
154         return res;
155     }
156     #undef lc
157     #undef rc
158 }sgt;
159 struct LCT{
160     int ch[mxn][2],fa[mxn];
161     bool rev[mxn];
162     int st[mxn],top;
163     inline bool isroot(int x){return (ch[fa[x]][0]!=x && ch[fa[x]][1]!=x);}
164     void PD(int rt){
165         if(rev[rt]){
166             rev[ch[rt][0]]^=1;    rev[ch[rt][1]]^=1;
167             swap(ch[rt][0],ch[rt][1]);
168             rev[rt]^=1;
169         }
170         return;
171     }
172     void rotate(int x){
173         int y=fa[x],z=fa[y],lc,rc;
174         if(ch[y][0]==x)lc=0;else lc=1; rc=lc^1;
175         if(!isroot(y)) ch[z][ch[z][1]==y]=x;
176         fa[x]=z;fa[y]=x;
177         fa[ch[x][rc]]=y;
178         ch[y][lc]=ch[x][rc]; ch[x][rc]=y;
179         return;
180     }
181     void Splay(int x){
182         st[top=1]=x;
183         for(int i=x;!isroot(i);i=fa[i])    st[++top]=fa[i];
184         while(top)PD(st[top--]);
185         while(!isroot(x)){
186             int y=fa[x],z=fa[y];
187             if(!isroot(y)){
188                 if((ch[z][0]==y)^(ch[y][0]==x))rotate(x);
189                 else rotate(y);
190             }
191             rotate(x);
192         }
193     }
194     void access(int x){
195         for(int y=0;x;x=fa[x]){
196             Splay(x);
197             if(ch[x][1]){
198                 int now=ch[x][1];    PD(now);
199                 while(ch[now][0]){now=ch[now][0];PD(now);}
200                 sgt.Q_UPD(now,1);
201             }
202             if(y){
203                 int now=y;    PD(now);
204                 while(ch[now][0]){now=ch[now][0];PD(now);}
205                 sgt.Q_UPD(now,-1);
206             }
207             ch[x][1]=y;
208             y=x;
209         }
210         return;
211     }
212     void mkroot(int x){
213         access(x);Splay(x);
214         rev[x]^=1;
215         nowroot=x;
216         return;
217     }
218 }LT;
219 void solve(){
220     char opt[10];int x;
221     while(m--){
222         scanf("%s%d",opt,&x);
223         if(opt[2]=='Q'){sgt.Query(x);continue;}//REQUEST
224         else if(opt[2]=='C'){LT.mkroot(x);continue;}//RECENTER
225         else if(opt[2]=='L'){LT.access(x);continue;}//RELEASE
226 //        else Debug();
227     }
228     return;
229 }
230 int main(){
231     int i,j;
232     n=read();m=read();
233     int u,v;
234     for(i=1;i<n;i++){
235         u=read();v=read();
236         add_edge(u,v);add_edge(v,u);
237     }
238     TC::DFS(1,0);
239     TC::DFS2(1,1);
240     for(i=1;i<=n;i++) LT.fa[i]=TC::t[i].fa;    
241     sgt.Build(1,n,1);
242     nowroot=1;
243     solve();
244     return 0;
245 }

 

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 408  Solved: 163
[Submit][Status][Discuss]

Description

黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒。这种病毒的繁殖和变异能力极强。为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒。
实验在一个封闭的局域网内进行。局域网内有n台计算机,编号为1~n。一些计算机之间通过网线直接相连,形成树形的结构。局域网中有一台特殊的计算机,称之为核心计算机。根据一些初步的研究,研究员们拟定了一个一共m步的实验。实验开始之前,核心计算机的编号为1,每台计算机中都有病毒的一个变种,而且每台计算机中的变种都不相同。实验中的每一步会是下面中的一种操作:
1、 RELEASE x
在编号为x的计算机中植入病毒的一个新变种。这个变种在植入之前不存在于局域网中。
2、 RECENTER x
将核心计算机改为编号为x的计算机。但是这个操作会导致原来核心计算机中的病毒产生新变种,并感染过来。换言之,假设操作前的核心计算机编号为y,相当于在操作后附加了一次RELEASE y的操作。
根据研究的结论,在植入一个新变种时,病毒会在局域网中搜索核心计算机的位置,并沿着网络中最短的路径感染过去。
而第一轮实验揭露了一个惊人的真相:病毒的不同变种是互斥的。新变种在感染一台已经被旧变种感染的电脑时,会把旧变种完全销毁之后再感染。但研究员发现了实现过程中的漏洞。如果新变种在感染过程中尚未销毁过这类旧变种,需要先花费1单位时间分析旧变种,才能销毁。如果之前销毁过这类旧变种,就可以认为销毁不花费时间。病毒在两台计算机之间的传播亦可认为不花费时间。
研究员对整个感染过程的耗时特别感兴趣,因为这是消灭病毒的最好时机。于是在m步实验之中,研究员有时还会做出如下的询问:
3、 REQUEST x
询问如果在编号为x的计算机的关键集合中的计算机中植入一个新变种,平均感染时间为多长。编号为y的计算机在编号为x的计算机的关键集合中,当且仅当从y沿网络中的最短路径感染到核心计算机必须经过x。由于有RECENTER操作的存在,这个集合并不一定是始终不变的。
至此,安全机构认为已经不需要实际的实验了,于是他们拜托你编写一个程序,模拟实验的结果,并回答所有的询问。

 

Input

输入的第一行包含两个整数n和m,分别代表局域网中计算机的数量,以及操作和询问的总数。
接下来n-1行,每行包含两个整数x和y,表示局域网中编号为x和y的计算机之间有网线直接相连。
接下来m行,每行包含一个操作或者询问,格式如问题描述中所述。
 

 

Output

对于每个询问,输出一个实数,代表平均感染时间。输出与答案的绝对误差不超过 10^(-6)时才会被视为正确。

 

Sample Input

8 6
1 2
1 3
2 8
3 4
3 5
3 6
4 7
REQUEST 7
RELEASE 3
REQUEST 3
RECENTER 5
RELEASE 2
REQUEST 1

Sample Output

4.0000000000
2.0000000000
1.3333333333

HINT

 

N < = 1 00 000 M < = 1 00 000

 

posted @ 2017-04-18 16:09  SilverNebula  阅读(311)  评论(0编辑  收藏  举报
AmazingCounters.com