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. root在x的子树内,查询整棵树去除掉包含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+;
  9. int n,m,x,y,cnt,dfn,rt=,first[N];
  10. int deep[N],in[N],out[N],fa[N][];
  11. char op[];
  12. int read()
  13. {
  14. int x=,f=;char c=getchar();
  15. while(c<''||c>''){if(c=='-')f=-;c=getchar();}
  16. while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
  17. return x*f;
  18. }
  19. struct edge{int to,next;}e[N<<];
  20. void ins(int u,int v){e[++cnt]=(edge){v,first[u]};first[u]=cnt;}
  21. struct SGT
  22. {
  23. int l[N*],r[N*];
  24. LL sum[N*],tag[N*];
  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)>>;
  29. build(lc(x),L,mid);build(rc(x),mid+,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]+);}
  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]=;
  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])>>;
  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=;
  51. int mid=(l[x]+r[x])>>;
  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]-;
  60. for(int i=;i>=;i--)
  61. if(d&(<<i))y=fa[y][i];
  62. return y;
  63. }
  64. void addson(int x,LL w)
  65. {
  66. if(x==rt)sgt.add(,,n,w);
  67. else if(in[rt]>=in[x]&&out[rt]<=out[x])
  68. {
  69. int t=find(x,rt);
  70. if(in[t]>)sgt.add(,,in[t]-,w);
  71. if(out[t]<n)sgt.add(,out[t]+,n,w);
  72. }
  73. else sgt.add(,in[x],out[x],w);
  74. }
  75. struct LCT
  76. {
  77. int c[N][],fa[N],in[N],out[N];
  78. bool rev[N];
  79. bool isroot(int x){return c[fa[x]][]!=x&&c[fa[x]][]!=x;}
  80. void flip(int x){swap(c[x][],c[x][]);rev[x]^=;}
  81. void down(int x){if(rev[x])flip(c[x][]),flip(c[x][]),rev[x]=;}
  82. void rotate(int x)
  83. {
  84. int y=fa[x],z=fa[y],l,r;
  85. if(c[y][]==x)l=;else l=;r=l^;
  86. if(!isroot(y)){if(c[z][]==y)c[z][]=x;else c[z][]=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][]==x)^(c[z][]==y))rotate(x);
  100. else rotate(y);
  101. }
  102. rotate(x);
  103. }
  104. }
  105. int top(int x){down(x);while(c[x][])x=c[x][],down(x);return x;}
  106. void access(int x)
  107. {
  108. int t=;
  109. while(x)
  110. {
  111. splay(x);
  112. if(c[x][])addson(top(c[x][]),);
  113. if(t)addson(top(t),-);
  114. c[x][]=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(,in[x],in[x],deep[x]);
  123. for(int i=;(<<i)<=deep[x];i++)
  124. fa[x][i]=fa[fa[x][i-]][i-];
  125. for(int i=first[x];i;i=e[i].next)
  126. {
  127. int to=e[i].to;
  128. if(to==fa[x][])continue;
  129. fa[to][]=lct.fa[to]=x;
  130. deep[to]=deep[x]+;dfs(to);
  131. }
  132. out[x]=dfn;
  133. }
  134. double request(int x)
  135. {
  136. if(x==rt)return 1.0*sgt.query(,,n)/n;
  137. if(in[rt]>=in[x]&&out[rt]<=out[x])
  138. {
  139. int t=find(x,rt);LL sum=;
  140. if(in[t]>)sum+=sgt.query(,,in[t]-);
  141. if(out[t]<n)sum+=sgt.query(,out[t]+,n);
  142. return 1.0*sum/(n-(out[t]-in[t]+));
  143. }
  144. return 1.0*sgt.query(,in[x],out[x])/(out[x]-in[x]+);
  145. }
  146. int main()
  147. {
  148. n=read();m=read();
  149. for(int i=;i<n;i++)x=read(),y=read(),ins(x,y),ins(y,x);
  150. sgt.build(,,n);deep[]=;dfs();
  151. while(m--)
  152. {
  153. scanf("%s",op);x=read();
  154. if(op[]=='Q')printf("%.10lf\n",request(x));
  155. else
  156. {
  157. lct.access(x);
  158. if(op[]=='C')lct.makeroot(x);
  159. }
  160. }
  161. return ;
  162. }

【bzoj 3779】重组病毒的更多相关文章

  1. bzoj 3779: 重组病毒 LCT+线段树+倍增

    题目: 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒. 实验在一个封闭 ...

  2. BZOJ 3779: 重组病毒(线段树+lct+树剖)

    题面 escription 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病 ...

  3. BZOJ 3779 重组病毒 LCT+线段树(维护DFS序)

    原题干(由于是权限题我就直接砸出原题干了,要看题意概述的话在下面): Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力 ...

  4. bzoj 3779 重组病毒——LCT维护子树信息

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3779 调了很久……已经懒得写题解了.https://www.cnblogs.com/Zinn ...

  5. bzoj 3779 重组病毒 —— LCT+树状数组(区间修改+区间查询)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3779 RELEASE操作可以对应LCT的 access,RECENTER则是 makeroo ...

  6. bzoj 3779: 重组病毒【LCT+线段树维护dfs序】

    %.8lf会WA!!%.8lf会WA!!%.8lf会WA!!要%.10lf!! 和4817有点像,但是更复杂. 首先对于操作一"在编号为x的计算机中植入病毒的一个新变种,在植入一个新变种时, ...

  7. bzoj 3779: 重组病毒

    一道好题~~ 一个点到根传染需要的时间是这段路径上不同颜色的数目,一个点子树到根平均传染时间就是加权平均数了(好像是废话). 所以只要用线段树维护dfs序就这个可以了,换根的话一个点的子树要么在dfs ...

  8. bzoj 3779 重组病毒 好题 LCT+dfn序+线段树分类讨论

    题目大意 1.将x到当前根路径上的所有点染成一种新的颜色: 2.将x到当前根路径上的所有点染成一种新的颜色,并且把这个点设为新的根: 3.查询以x为根的子树中所有点权值的平均值. 分析 原题codec ...

  9. BZOJ 3779 重组病毒 ——LCT 线段树

    发现操作一很像一个LCT的access的操作. 然后答案就是路径上的虚边的数量. 然后考虑维护每一个点到根节点虚边的数量, 每次断开一条偏爱路径的时候,子树的值全部+1, 连接一条偏爱路径的时候,子树 ...

  10. 【BZOJ】3779 重组病毒

    [算法]Link-Cut Tree+线段树(维护DFS序) [题解]整整三天……T_T 这篇题解比较资瓷:permui 这道题虽然树形态没有变化,但用lct写的原因在于把题目中的操作一进行了神转化:每 ...

随机推荐

  1. [SHOI2014]概率充电器(概率+换根dp)

    著名的电子产品品牌SHOI 刚刚发布了引领世界潮流的下一代电子产品—— 概率充电器: “采用全新纳米级加工技术,实现元件与导线能否通电完全由真随机数决 定!SHOI 概率充电器,您生活不可或缺的必需品 ...

  2. 为什么在Python里推荐使用多进程而不是多线程?(为什么python多线程无法增加CPU使用率?)

    最近在看Python的多线程,经常我们会听到老手说:“Python下多线程是鸡肋,推荐使用多进程!”,但是为什么这么说呢? 要知其然,更要知其所以然.所以有了下面的深入研究: 首先强调背景:     ...

  3. Python模块之time、random、os、sys、序列化、re

    Time模块 和时间有关系的我们就要用到时间模块.在使用模块之前,应该首先导入这个模块. #常用方法 1.time.sleep(secs) (线程)推迟指定的时间运行.单位为秒. 2.time.tim ...

  4. Jquery Mobile列表

    向 <ol> 或 <ul> 元素添加 data-role="listview" 1.圆角和外边距 :data-inset="true" ...

  5. halcon图像处理的基本思路

    原图素材,1.jpg 过程图: 结果图: 代码及注意事项: read_image (Image, 'C:/Users/Jv/Desktop/1.jpg') rgb1_to_gray (Image, G ...

  6. FFT笔记

    蝴蝶操作和Rader排序 蝴蝶操作的定义: 雷德(Rader)算法 (Gold Rader bit reversal algorithm) 按自然顺序排列的二进制数,其下面一个数总是比其上面一个数大1 ...

  7. 下载神器(vip下载速度)

    简单介绍: 用过好几款下载神器,现在推荐一款比较好用的软件,强调一点本软件强调开源免费的原则,禁止一切人员在其中收取费用. 我把这款软件放到了,自己的百度云盘. 神器的使用教程如下: 百度云下载连接: ...

  8. Linux中sed的用法实践

    Linux中sed的用法实践 参考资料:https://www.cnblogs.com/emanlee/archive/2013/09/07/3307642.html http://www.fn139 ...

  9. flask get和post请求使用

    直接看代码 #-*-coding:utf-8-*- from flask import Flask,url_for,redirect,render_template,request app = Fla ...

  10. JAVA核心技术I---JAVA基础知识(对象与类)

    一:规范 将每一个类存在一个单独的源文件中 Employee.java public class Employee { private int age; private float salay; pr ...