发现操作一很像一个LCT的access的操作。

然后答案就是路径上的虚边的数量。

然后考虑维护每一个点到根节点虚边的数量,

每次断开一条偏爱路径的时候,子树的值全部+1,

连接一条偏爱路径的时候,子树的值全部-1。

然后就用线段树维护DFS序就可以了。

但是还有一个换根的操作,发现线段树不能换根,所以直接在线段树上分类讨论进行更新就可以了。

然后makeroot操作就可以换根了。

#include <map>
#include <ctime>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define ll long long
#define maxn 200005 int data[200005]; int n,m,dfn[maxn],id[maxn],f[maxn][21],in[maxn],out[maxn];
int tim[maxn],dep[maxn]; char opt[11];int x; namespace ST{
ll sum[maxn<<3],tag[maxn<<3];
void update(int o)
{
sum[o]=sum[o<<1]+sum[o<<1|1];
return ;
}
void pushdown(int o,int l,int r)
{
if (tag[o]!=0)
{
int mid=l+r>>1;
sum[o<<1]+=(mid-l+1)*tag[o];
sum[o<<1|1]+=(r-mid)*tag[o];
tag[o<<1]+=tag[o];
tag[o<<1|1]+=tag[o];
tag[o]=0;
}
return ;
}
void build(int o,int l,int r)
{
if (l==r)
{
sum[o]=data[l];
tag[l]=0;
return ;
}
int mid=l+r>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
update(o);
return ;
}
void modify(int o,int l,int r,int L,int R,int f)
{
if (L<=l&&r<=R)
{
tag[o]+=f;
sum[o]+=(r-l+1)*f;
return ;
}
pushdown(o,l,r);
int mid=l+r>>1;
if (R<=mid) return modify(o<<1,l,mid,L,R,f),update(o);
else if (L>mid) return modify(o<<1|1,mid+1,r,L,R,f),update(o);
else return modify(o<<1,l,mid,L,R,f),modify(o<<1|1,mid+1,r,L,R,f),update(o);
}
ll querysum(int o,int l,int r,int L,int R)
{
if (L<=l&&r<=R) return sum[o];
pushdown(o,l,r);
int mid=l+r>>1;
if (R<=mid) return querysum(o<<1,l,mid,L,R);
else if (L>mid) return querysum(o<<1|1,mid+1,r,L,R);
else return querysum(o<<1,l,mid,L,R)+querysum(o<<1|1,mid+1,r,L,R);
}
int Second_LCA(int a,int b)
{
if (dep[a]>dep[b]) swap(a,b);
int dist=dep[b]-dep[a]-1; //printf("dist %d\n",dist);
D(i,20,0) if ((dist>>i)&1) b=f[b][i];
return b;
}
int LCA(int a,int b)
{
if (dep[a]>dep[b]) swap(a,b);
int dist=dep[b]-dep[a];
D(i,20,0) if ((dist>>i)&1) b=f[b][i];
if (a==b) return b;
D(i,20,0) if (f[b][i]!=f[a][i]) b=f[b][i],a=f[a][i];
return f[b][0];
}
double query(int rt,int o)
{
if (o==rt)
{
return (1.0*querysum(1,1,n,1,n))/(1.0*n);
}
else if (LCA(rt,o)==rt) return (querysum(1,1,n,in[o],out[o]))/(1.0*(out[o]-in[o]+1));
else if (LCA(rt,o)==o)
{
int tmp=Second_LCA(rt,o);
return (1.0*querysum(1,1,n,1,n)-1.0*querysum(1,1,n,in[tmp],out[tmp]))/(1.0*(n-out[tmp]+in[tmp]-1));
}
else
{
return (1.0*querysum(1,1,n,in[o],out[o]))/(1.0*(out[o]-in[o]+1));
}
}
void add(int rt,int o,int f)
{
if (!o) return ;
if (o==rt) return modify(1,1,n,1,n,f);
else if (LCA(rt,o)==rt) return modify(1,1,n,in[o],out[o],f);
else if (LCA(rt,o)==o)
{
int tmp=Second_LCA(rt,o);
modify(1,1,n,1,n,f);
modify(1,1,n,in[tmp],out[tmp],-f);
}
else return modify(1,1,n,in[o],out[o],f);
}
} namespace LCT{
int rev[maxn],ch[maxn][2],fa[maxn];
int sta[maxn],top,rt=1;
bool isroot(int o)
{return (ch[fa[o]][0]!=o)&&(ch[fa[o]][1]!=o);}
void pushdown(int o)
{
if (rev[o])
{
rev[o]^=1;
rev[ch[o][0]]^=1;
rev[ch[o][1]]^=1;
swap(ch[o][0],ch[o][1]);
}
}
void rot(int x)
{
int y=fa[x],z=fa[y],l,r;
if (ch[y][0]==x) l=0; else l=1; r=l^1;
if (!isroot(y))
{
if (ch[z][0]==y) ch[z][0]=x;
else ch[z][1]=x;
}
fa[x]=z; fa[y]=x; fa[ch[x][r]]=y;
ch[y][l]=ch[x][r]; ch[x][r]=y;
}
void splay(int x)
{
sta[top=1]=x;
for (int i=x;!isroot(i);i=fa[i]) sta[++top]=fa[i];
while (top) pushdown(sta[top--]); while (!isroot(x))
{
int y=fa[x];
if (!isroot(y))
{
int z=fa[y];
if (ch[y][0]==x^ch[z][0]==y) rot(x);
else rot(y);
}
rot(x);
}
}
int find(int x)
{
pushdown(x);
while (ch[x][0]) x=ch[x][0],pushdown(x);
return x;
}
void access(int x)
{
for (int t=0;x;t=x,x=fa[x])
{
splay(x);
ST::add(rt,find(ch[x][1]),1);
ch[x][1]=t;
ST::add(rt,find(t),-1);
}
}
void makeroot(int x)
{
access(x);
splay(x);
rev[x]^=1;
rt=x;
}
} namespace Graph{
int h[maxn],to[maxn],ne[maxn],en=0,tot=0;
void add(int a,int b){to[en]=b;ne[en]=h[a];h[a]=en++;}
void dfs(int o,int fa)
{
in[o]=dfn[o]=++tot; id[tot]=o; f[o][0]=fa;
for (int i=h[o];i>=0;i=ne[i])
if (to[i]!=fa) dep[to[i]]=dep[o]+1,tim[to[i]]=tim[o]+1,dfs(to[i],o);
out[o]=tot;
}
} int main()
{
memset(Graph::h,-1,sizeof Graph::h);
scanf("%d%d",&n,&m);
F(i,1,n-1)
{
int a,b;
scanf("%d%d",&a,&b);
Graph::add(a,b);Graph::add(b,a);
}
tim[1]=1; Graph::dfs(1,0);
F(i,1,n) LCT::fa[i]=f[i][0];
F(i,1,20) F(j,1,n) f[j][i]=f[f[j][i-1]][i-1];
F(i,1,n) data[dfn[i]]=tim[i];
ST::build(1,1,n);
F(i,1,m)
{
scanf("%s%d",opt,&x);
switch(opt[2])
{
case 'Q': printf("%.10lf\n",ST::query(LCT::rt,x)); break;
case 'C': LCT::makeroot(x); break;
case 'L': LCT::access(x); break;
}
}
}

  

BZOJ 3779 重组病毒 ——LCT 线段树的更多相关文章

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

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

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

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

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

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

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

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

  5. 【BZOJ-3779】重组病毒 LinkCutTree + 线段树 + DFS序

    3779: 重组病毒 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 224  Solved: 95[Submit][Status][Discuss] ...

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

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

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

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

  8. bzoj 3779: 重组病毒

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

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

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

随机推荐

  1. Python实现扫描作业配置自动化

    持续集成平台接入扫描作业是一项繁琐而又需要细致的工作,于是趁着闲暇时间,将代码扫描作业用Python代码实现了配置自动化. 每次配置作业的过程中,都会在checkcode1或者checkcode3上 ...

  2. PG extract 函数示例

    pg 对时间的处理还是很灵活的, + - * /  都有支持 期间有个extract 函数还是很有用的,我们先来看看几个例子:[code] postgres=# select extract(epoc ...

  3. perl在linux下通过date获取当前时间

    perl处理文件的时候最好添加上 处理的时间戳,获取系统的时间又多种方法,但是反引号是最原始的,不需要其他外界条件和lib的支持. my $now = `date "+%F %T" ...

  4. codevs 1155 金明的预算方案

    时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题目描述 Description 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房 ...

  5. 关于ubuntu终端全屏的时候不能显示底部

    最近在win7的电脑上装了ubuntu,也就是双系统.打算之后工作就直接进入ubuntu,减少之前win7和虚拟机之间的切换.进入ubuntu后,发现一个奇怪的问题是,在终端全屏的时候,底部总是有几行 ...

  6. CNNs 在图像分割中应用简史: 从R-CNN到Mask R-CNN

    作者:嫩芽33出处:http://www.cnblogs.com/nenya33/p/6756024.html 版权:本文版权归作者和博客园共有 转载:欢迎转载,但未经作者同意,必须保留此段声明:必须 ...

  7. Android(java)学习笔记147:自定义SmartImageView(继承自ImageView,扩展功能为自动获取网络路径图片)

    1. 有时候Android系统配置的UI控件,不能满足我们的需求,Android开发做到了一定程度,多少都会用到自定义控件,一方面是更加灵活,另一方面在大数据量的情况下自定义控件的效率比写布局文件更高 ...

  8. C#中加锁问题

    今天在工作中遇到了一个问题 当我使用多线程访问同一个方法资源时,为了不对结果进行冲突于是加了个死锁,还遇到了一些坑,特此来进行一些记录 static object obj=new object(); ...

  9. Python基础篇 -- 字典

    字典 dict. 以 {} 表示, 每一项用逗号隔开, 内部元素用 key: value的形式来保存数据 例子: dict.{"JJ":"林俊杰"," ...

  10. shell脚本,编程题练习。

    题目是:将 文件file为 b+b+b+b+b+b+b+b 变为 b+b=b+b=b+b=b+b 解答方法如下: