题目描述

黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒。这种病毒的繁殖和变异能力极强。为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒。
实验在一个封闭的局域网内进行。局域网内有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操作的存在,这个集合并不一定是始终不变的。
至此,安全机构认为已经不需要实际的实验了,于是他们拜托你编写一个程序,模拟实验的结果,并回答所有的询问。

题解

我们可以来观察这两个操作。

1、将当前点到根染上一种新的颜色,这意味着这条路径上的点到其他点颜色是不一样的。

2、对x点进行操作1,然后把x作为根。

我们发现这两个操作和LCT中的access和makeroot一毛一样,重边代表两点颜色相同,轻边代表颜色不同。

然后就用LCT维护这个过程。

但要求区间查询,所以再加上线段树维护dfs序。

access时,如果断开一条重边,那么子树里答案要+1,如果连上一条重边,那么子树-1。

然后换根的话和遥远的国度那题一样,讨论一下当前点和根的关系就好了。

注意:线段树区间加别写错,子树加的时候要先findroot一下找到真正的子树根。

代码

#include<iostream>
#include<cstdio>
#define N 100002
using namespace std;
typedef long long ll;
char s[];
ll tr[N<<],la[N<<];
int ch[N][],fa[N],dfn[N],size[N],root,n,m,tot,top,head[N],deep[N];
int p[N][];
bool rev[N];
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
inline void pushd(int cnt,int l1,int l2){
tr[cnt<<]+=la[cnt]*l1;la[cnt<<]+=la[cnt];
tr[cnt<<|]+=la[cnt]*l2;la[cnt<<|]+=la[cnt];
la[cnt]=;
}
void upd(int cnt,int l,int r,int L,int R,int x){
if(L>R)return;
if(l>=L&&r<=R){tr[cnt]+=1ll*(r-l+)*x;la[cnt]+=x;return;}
int mid=(l+r)>>;
if(la[cnt])pushd(cnt,mid-l+,r-mid);
if(mid>=L)upd(cnt<<,l,mid,L,R,x);
if(mid<R)upd(cnt<<|,mid+,r,L,R,x);
tr[cnt]=tr[cnt<<]+tr[cnt<<|];
}
ll query(int cnt,int l,int r,int L,int R){
if(L>R)return ;
if(l>=L&&r<=R)return tr[cnt];
int mid=(l+r)>>;ll ans=;
if(la[cnt])pushd(cnt,mid-l+,r-mid);
if(mid>=L)ans+=query(cnt<<,l,mid,L,R);
if(mid<R)ans+=query(cnt<<|,mid+,r,L,R);
return ans;
}
#define ls ch[x][0]
#define rs ch[x][1]
inline bool ge(int x){return ch[fa[x]][]==x;}
inline bool isroot(int x){return ch[fa[x]][]!=x&&ch[fa[x]][]!=x;}
inline void rotate(int x){
int y=fa[x],o=ge(x);
ch[y][o]=ch[x][o^];fa[ch[y][o]]=y;
if(!isroot(y))ch[fa[y]][ge(y)]=x;fa[x]=fa[y];
fa[y]=x;ch[x][o^]=y;
}
inline void pushdown(int x){if(rev[x]){rev[x]^=;rev[ls]^=;rev[rs]^=;swap(ls,rs);}}
inline void _pushdown(int x){if(!isroot(x))_pushdown(fa[x]);pushdown(x);}
inline void splay(int x){
_pushdown(x);
while(!isroot(x)){
int y=fa[x];
if(isroot(y))rotate(x);
else rotate(ge(x)==ge(y)?y:x),rotate(x);
}
}
inline int jump(int x,int y){
if(y<=)return x;
for(int i=;i>=;--i)if((<<i)&y)x=p[x][i];
return x;
}
inline void jia(int x,int tag){
if(root==x)upd(,,n,,n,tag);
else
if(dfn[root]>=dfn[x]&&dfn[root]<=dfn[x]+size[x]-){
int y=jump(root,deep[root]-deep[x]-);
upd(,,n,,dfn[y]-,tag);upd(,,n,dfn[y]+size[y],n,tag);
}
else upd(,,n,dfn[x],dfn[x]+size[x]-,tag);
}
inline int findroot(int x){
pushdown(x);
while(ch[x][])x=ch[x][],pushdown(x);
return x;
}
inline void access(int x){
for(int y=;x;y=x,x=fa[x]){
splay(x);
if(ch[x][])jia(findroot(ch[x][]),);if(y)jia(findroot(y),-);
ch[x][]=y;
}
}
inline void makeroot(int x){access(x);splay(x);rev[x]^=;}
struct edge{int n,to;}e[N<<];
inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;}
void dfs(int u,int f){
dfn[u]=++top;size[u]=;deep[u]=deep[f]+;
for(int i=;(<<i)<=deep[u];++i)p[u][i]=p[p[u][i-]][i-];
upd(,,n,dfn[u],dfn[u],deep[u]);
for(int i=head[u];i;i=e[i].n)if(e[i].to!=f){
int v=e[i].to;fa[v]=u;p[v][]=u;
dfs(v,u);size[u]+=size[v];
}
}
int main(){
n=rd();m=rd();int x,y;
for(int i=;i<n;++i){x=rd();y=rd();add(x,y);add(y,x);}
dfs(,);root=;
for(int i=;i<=m;++i){
scanf("%s",s);x=rd();
if(s[]=='L')access(x);
else if(s[]=='C')makeroot(x),root=x;
else{
double sum=;
if(root==x)sum=(double)query(,,n,,n)/n;
else
if(dfn[root]>=dfn[x]&&dfn[root]<=dfn[x]+size[x]-){
int y=jump(root,deep[root]-deep[x]-);
sum=(double)(query(,,n,,dfn[y]-)+query(,,n,dfn[y]+size[y],n))/(n-size[y]);
}
else sum=(double)query(,,n,dfn[x],dfn[x]+size[x]-)/size[x];
printf("%.10lf\n",sum);
}
}
return ;
}

BZOJ3779重组病毒LCT的更多相关文章

  1. [BZOJ3779]重组病毒(LCT+DFS序线段树)

    同[BZOJ4817]树点涂色,只是多了换根操作,分类讨论下即可. #include<cstdio> #include<algorithm> #define lc ch[x][ ...

  2. 【BZOJ3779】重组病毒 LCT+DFS序

    [BZOJ3779]重组病毒 Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策 ...

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

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

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

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

  5. 【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询

    题目描述 给出一棵n个节点的树,每一个节点开始有一个互不相同的颜色,初始根节点为1. 定义一次感染为:将指定的一个节点到根的链上的所有节点染成一种新的颜色,代价为这条链上不同颜色的数目. 现有m次操作 ...

  6. bzoj千题计划274:bzoj3779: 重组病毒

    http://www.lydsy.com/JudgeOnline/problem.php?id=3779 有一棵树,初始每个节点有不同的颜色 操作1:根节点到x的路径上的点 染上一种没有出现过的颜色 ...

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

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

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

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

  9. bzoj3779: 重组病毒 link-cut-tree

    题目传送门 这道题看了做了个神转换.....推荐个博客给各位大爷看看吧神犇传送门 代码敲了半天....题目也读了半天 线段树维护的东西很容易和lct混在一起 调了调能过也是很开心啊 运气比较好吧233 ...

随机推荐

  1. Is there a way to avoid undeployment memory leaks in Tomcat?

    tomcat 项目部署问题 - yshy - 博客园http://www.cnblogs.com/yshyee/p/3973293.html jsp - tomcat - their classes ...

  2. Git之项目使用

    现在最为盛行的版本控制器,非git莫属了, 那就看看在项目中我们是如何使用它的吧 一. 在已经存在秘钥对的情况下,我们需要在本地进行相关配置 git config --global user.name ...

  3. anaconda + VSCode + 生产环境配置

    1. 修改jupyter notebook 默认路径: 进入anaconda 命令行, jupyter notebook --generate-config   生成配置文件, 该文件在    本机用 ...

  4. Laravel Providers——服务提供者的注册与启动源码解析

      本文 GitBook 地址: https://www.gitbook.com/book/leoyang90/laravel-source-analysishttps://learnku.com/a ...

  5. 通过event记录sql

    providers EventServiceProvider.php 添加 protected $listen = [ 'Illuminate\Database\Events\QueryExecute ...

  6. oss上传和下载的笔记

    <<<<<<<<<对oss操作,上传文件>>>>>>>>>>>>>& ...

  7. Day5-1 面向对象和面向过程

    摘要: 类的定义 类的增删改查 对象的增删改查 对象的查找和绑定 面向对象和面向过程的区别: 1.面向过程就像是工厂的流水线,按部就班的有序的工作. 优点:把复杂的问题简单化 缺点:可扩展性差.一个步 ...

  8. Day 4-4 shutil模块

    常用方法: import shutil f = open("conf.ini", "r") f1 = open("shutil.ini", ...

  9. Java 多线程概述

    几乎所有的操作系统都支持同时运行多个任务,一 个任务通常就是一个程序,每个运行中的程序就是一个进程.当一个程序运行时,内部可能包含了多个顺序执行流,每个顺序执行流就是一个线程. 线程和进程 几乎所有的 ...

  10. 转 Pycharm及python安装详细教程

    转 : http://blog.csdn.net/qq_29883591/article/details/52664478 首先我们来安装Python 1.首先进入网站下载:点击打开链接(或自己输入网 ...