【bzoj 3779】重组病毒

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<=100000 ,M<=100000

 

调了几个世纪终于调出来了……LCT+dfs序线段树。

令每个点权值为这个点到根的路径上虚边数+1,一开始时都是虚边,点权即为深度。

操作1可以神转换为access。在access过程中,当前节点的右儿子所代表的子树整体权值+1(因为虚边+1),而即将拼接过来的子树整体权值-1。

操作2因为有换根操作,所以需要分类讨论一波(以下结论画图易得):

1. x=root,查询整棵树;

2. root不在x的子树内,查询原树中x的子树;

3. rootx的子树内,查询整棵树去除掉包含root的以x的亲儿子为根的子树。

然后就可以开始瞎搞啦✔

 

Update:原来的代码有一点问题……重新写了一份。

  1 #include<cstdio>
  2 #include<algorithm> 
  3 #include<cstring>
  4 #define LL long long
  5 #define lc(x) x<<1
  6 #define rc(x) x<<1|1
  7 using namespace std;
  8 const int N=1e5+5;
  9 int n,m,x,y,cnt,dfn,rt=1,first[N];
 10 int deep[N],in[N],out[N],fa[N][18];
 11 char op[15];
 12 int read()
 13 {
 14     int x=0,f=1;char c=getchar();
 15     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
 16     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
 17     return x*f;
 18 }
 19 struct edge{int to,next;}e[N<<1];
 20 void ins(int u,int v){e[++cnt]=(edge){v,first[u]};first[u]=cnt;}
 21 struct SGT
 22 {
 23     int l[N*4],r[N*4];
 24     LL sum[N*4],tag[N*4];
 25     void build(int x,int L,int R)
 26     {
 27         l[x]=L;r[x]=R;if(L==R)return;
 28         int mid=(L+R)>>1;
 29         build(lc(x),L,mid);build(rc(x),mid+1,R);
 30     }
 31     void up(int x){sum[x]=sum[lc(x)]+sum[rc(x)];}
 32     void qadd(int x,LL w){tag[x]+=w;sum[x]+=w*(r[x]-l[x]+1);}
 33     void down(int x)
 34     {
 35         if(!tag[x])return;
 36         qadd(lc(x),tag[x]);qadd(rc(x),tag[x]);
 37         tag[x]=0;
 38     }
 39     void add(int x,int L,int R,LL w)
 40     {
 41         if(L<=l[x]&&r[x]<=R){qadd(x,w);return;}
 42         down(x);int mid=(l[x]+r[x])>>1;
 43         if(L<=mid)add(lc(x),L,R,w);
 44         if(R>mid)add(rc(x),L,R,w);
 45         up(x);
 46     }
 47     LL query(int x,int L,int R)
 48     {
 49         if(L<=l[x]&&r[x]<=R)return sum[x];
 50         down(x);LL ans=0;
 51         int mid=(l[x]+r[x])>>1;
 52         if(L<=mid)ans+=query(lc(x),L,R);
 53         if(R>mid)ans+=query(rc(x),L,R);
 54         return ans;
 55     }
 56 }sgt;
 57 int find(int x,int y)
 58 {
 59     int d=deep[y]-deep[x]-1;
 60     for(int i=16;i>=0;i--)
 61         if(d&(1<<i))y=fa[y][i];
 62     return y;
 63 }
 64 void addson(int x,LL w)
 65 {
 66     if(x==rt)sgt.add(1,1,n,w);
 67     else if(in[rt]>=in[x]&&out[rt]<=out[x])
 68     {
 69         int t=find(x,rt);
 70         if(in[t]>1)sgt.add(1,1,in[t]-1,w);
 71         if(out[t]<n)sgt.add(1,out[t]+1,n,w);
 72     }
 73     else sgt.add(1,in[x],out[x],w);
 74 }
 75 struct LCT
 76 {
 77     int c[N][2],fa[N],in[N],out[N];
 78     bool rev[N];
 79     bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
 80     void flip(int x){swap(c[x][0],c[x][1]);rev[x]^=1;}
 81     void down(int x){if(rev[x])flip(c[x][0]),flip(c[x][1]),rev[x]=0;}
 82     void rotate(int x)
 83     {
 84         int y=fa[x],z=fa[y],l,r;
 85         if(c[y][0]==x)l=0;else l=1;r=l^1;
 86         if(!isroot(y)){if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;}
 87         fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
 88         c[y][l]=c[x][r];c[x][r]=y;
 89     }
 90     void relax(int x){if(!isroot(x))relax(fa[x]);down(x);}
 91     void splay(int x)
 92     {
 93         relax(x);
 94         while(!isroot(x))
 95         {
 96             int y=fa[x],z=fa[y];
 97             if(!isroot(y))
 98             {
 99                 if((c[y][0]==x)^(c[z][0]==y))rotate(x);
100                 else rotate(y);
101             }
102             rotate(x);
103         }
104     }
105     int top(int x){down(x);while(c[x][0])x=c[x][0],down(x);return x;}
106     void access(int x)
107     {
108         int t=0;
109         while(x)
110         {
111             splay(x);
112             if(c[x][1])addson(top(c[x][1]),1);
113             if(t)addson(top(t),-1);
114             c[x][1]=t;t=x;x=fa[x];
115         }
116     }
117     void makeroot(int x){splay(x);rt=x;flip(x);}
118 }lct;
119 void dfs(int x)
120 {
121     in[x]=++dfn;
122     sgt.add(1,in[x],in[x],deep[x]);
123     for(int i=1;(1<<i)<=deep[x];i++)
124         fa[x][i]=fa[fa[x][i-1]][i-1];
125     for(int i=first[x];i;i=e[i].next)
126     {
127         int to=e[i].to;
128         if(to==fa[x][0])continue;
129         fa[to][0]=lct.fa[to]=x;
130         deep[to]=deep[x]+1;dfs(to);
131     }
132     out[x]=dfn;
133 }
134 double request(int x)
135 {
136     if(x==rt)return 1.0*sgt.query(1,1,n)/n;
137     if(in[rt]>=in[x]&&out[rt]<=out[x])
138     {
139         int t=find(x,rt);LL sum=0;
140         if(in[t]>1)sum+=sgt.query(1,1,in[t]-1);
141         if(out[t]<n)sum+=sgt.query(1,out[t]+1,n);
142         return 1.0*sum/(n-(out[t]-in[t]+1));
143     }
144     return 1.0*sgt.query(1,in[x],out[x])/(out[x]-in[x]+1);
145 }
146 int main()
147 {
148     n=read();m=read();
149     for(int i=1;i<n;i++)x=read(),y=read(),ins(x,y),ins(y,x);
150     sgt.build(1,1,n);deep[1]=1;dfs(1);
151     while(m--)
152     {
153         scanf("%s",op);x=read();
154         if(op[2]=='Q')printf("%.10lf\n",request(x));
155         else
156         {
157             lct.access(x);
158             if(op[2]=='C')lct.makeroot(x);
159         }
160     }
161     return 0;
162 }
View Code

 

posted @ 2017-06-25 12:32  Zsnuo  阅读(837)  评论(2编辑  收藏  举报