分析

其实其他的题解说的都很清楚了。

一个点出发感染到根结点所花费的时间是路径上虚边的条数+1。

RELEASE相当于\(access()\)。

RECENTER相当于\(makeroot()\)。(虽然换根和打通路径的先后顺序不同但仔细想想本质其实是一样的)

所以我们可以通过维护一棵LCT来快速知道哪些结点与其父亲结点的连边由实变虚或由虚变实。

剩下的就是[BZOJ3083]遥远的国度了。

时间复杂度\(O(nlog^2n)\)。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <vector>
#define rin(i,a,b) for(int i=(a);i<=(b);i++)
#define rec(i,a,b) for(int i=(a);i>=(b);i--)
#define trav(i,a) for(int i=head[(a)];i;i=e[i].nxt)
using std::cin;
using std::cout;
using std::endl;
typedef long long LL; inline int read(){
int x=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x;
} const int MAXN=100005;
int n,m,root;
std::vector<int> e[MAXN],ee[MAXN];
int fa[MAXN],dep[MAXN],siz[MAXN],id[MAXN],num[MAXN],tot;
int sta[MAXN],top;
int ql,qr;
LL sum[MAXN<<2],atag[MAXN<<2],kk;
char opt[10];
struct lct{
int fa,ch[2];
int tag;
}a[MAXN]; inline void add_edge(int bg,int ed){
e[bg].push_back(ed);
} void dfs(int x,int pre,int depth){
fa[x]=pre;
a[x].fa=pre;
dep[x]=depth;
id[x]=++tot;
num[tot]=x;
siz[x]=1;
rin(i,0,(int)e[x].size()-1){
int ver=e[x][i];
if(ver==pre) continue;
ee[x].push_back(ver);
dfs(ver,x,depth+1);
siz[x]+=siz[ver];
}
} inline void subupd(int x,LL kkk); inline double subquery(int x); #define lc a[x].ch[0]
#define rc a[x].ch[1]
inline bool isroot(int x){
return a[a[x].fa].ch[0]!=x&&a[a[x].fa].ch[1]!=x;
} inline void pushr(int x){
std::swap(lc,rc);
a[x].tag^=1;
} inline void pushdown(int x){
if(!a[x].tag) return;
if(lc) pushr(lc);
if(rc) pushr(rc);
a[x].tag=0;
} inline void rotate(int x){
int y=a[x].fa,z=a[y].fa;
int f=(a[y].ch[1]==x),g=a[x].ch[f^1];
if(!isroot(y)) a[z].ch[a[z].ch[1]==y]=x;
a[x].ch[f^1]=y;
a[y].ch[f]=g;
if(g) a[g].fa=y;
a[y].fa=x;
a[x].fa=z;
} inline void splay(int x){
int y=x,z=0;
top=1;
sta[1]=y;
while(!isroot(y)) sta[++top]=y=a[y].fa;
while(top) pushdown(sta[top--]);
while(!isroot(x)){
y=a[x].fa,z=a[y].fa;
if(!isroot(y)){
if((a[y].ch[0]==x)==(a[z].ch[0]==y)) rotate(y);
else rotate(x);
}
rotate(x);
}
} inline int findroot(int x){
while(pushdown(x),lc) x=lc;
return x;
} inline void access(int x){
for(int y=0;x;x=a[y=x].fa){
splay(x);
if(rc){
subupd(findroot(rc),1);
}
rc=y;
if(rc){
subupd(findroot(rc),-1);
}
}
} inline void makeroot(int x){
access(x);
splay(x);
pushr(x);
}
#undef lc
#undef rc #define mid ((l+r)>>1)
#define lc (o<<1)
#define rc ((o<<1)|1)
inline void segpushdown(int o,int l,int r){
if(!atag[o]) return;
sum[lc]+=atag[o]*(mid-l+1);
sum[rc]+=atag[o]*(r-mid);
atag[lc]+=atag[o];
atag[rc]+=atag[o];
atag[o]=0;
} void build(int o,int l,int r){
if(l==r){
sum[o]=dep[num[l]];
return;
}
build(lc,l,mid);
build(rc,mid+1,r);
sum[o]=sum[lc]+sum[rc];
} void upd(int o,int l,int r){
if(ql>qr) return;
if(ql<=l&&r<=qr){
sum[o]+=kk*(r-l+1);
atag[o]+=kk;
return;
}
segpushdown(o,l,r);
if(mid>=ql) upd(lc,l,mid);
if(mid<qr) upd(rc,mid+1,r);
sum[o]=sum[lc]+sum[rc];
} LL query(int o,int l,int r){
if(ql>qr) return 0;
if(ql<=l&&r<=qr) return sum[o];
segpushdown(o,l,r);
LL ret=0;
if(mid>=ql) ret+=query(lc,l,mid);
if(mid<qr) ret+=query(rc,mid+1,r);
return ret;
}
#undef mid
#undef lc
#undef rc inline void subupd(int x,LL kkk){
kk=kkk;
if(id[root]<id[x]||id[root]>id[x]+siz[x]-1){
ql=id[x],qr=id[x]+siz[x]-1;
upd(1,1,n);
return;
}
else if(root==x){
ql=1,qr=n;
upd(1,1,n);
return;
}
else{
int l=0,r=(int)ee[x].size()-1,ver=0;
while(l<=r){
int mid=((l+r)>>1),verr=ee[x][mid];
if(id[verr]<=id[root]) ver=verr,l=mid+1;
else r=mid-1;
}
ql=1,qr=id[ver]-1;
upd(1,1,n);
ql=id[ver]+siz[ver],qr=n;
upd(1,1,n);
}
} inline double subquery(int x){
if(id[root]<id[x]||id[root]>id[x]+siz[x]-1){
ql=id[x],qr=id[x]+siz[x]-1;
return (double)query(1,1,n)/siz[x];
}
else if(root==x){
ql=1,qr=n;
return (double)query(1,1,n)/n;
}
else{
int l=0,r=(int)ee[x].size()-1,ver=0;
LL ret=0;
while(l<=r){
int mid=((l+r)>>1),verr=ee[x][mid];
if(id[verr]<=id[root]) ver=verr,l=mid+1;
else r=mid-1;
}
ql=1,qr=id[ver]-1;
ret+=query(1,1,n);
ql=id[ver]+siz[ver],qr=n;
ret+=query(1,1,n);
return (double)ret/(n-siz[ver]);
}
} int main(){
n=read(),m=read();
rin(i,2,n){
int u=read(),v=read();
add_edge(u,v);
add_edge(v,u);
}
root=1;
dfs(1,0,1);
build(1,1,n);
while(m--){
scanf("%s",opt+1);
int x=read();
if(opt[3]=='L'){
access(x);
}
else if(opt[3]=='C'){
makeroot(x);
root=x;
}
else{
printf("%.10lf\n",subquery(x));
}
}
return 0;
}

[BZOJ3779]重组病毒:Link-Cut Tree+线段树的更多相关文章

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

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

  2. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

  3. LCT(link cut tree) 动态树

    模板参考:https://blog.csdn.net/saramanda/article/details/55253627 综合各位大大博客后整理的模板: #include<iostream&g ...

  4. Link Cut Tree 动态树 小结

    动态树有些类似 树链剖分+并查集 的思想,是用splay维护的 lct的根是动态的,"轻重链"也是动态的,所以并没有真正的轻重链 动态树的操作核心是把你要把 修改/询问/... 等 ...

  5. 洛谷.3690.[模板]Link Cut Tree(动态树)

    题目链接 LCT(良心总结) #include <cstdio> #include <cctype> #include <algorithm> #define gc ...

  6. 洛谷P3690 Link Cut Tree (动态树)

    干脆整个LCT模板吧. 缺个链上修改和子树操作,链上修改的话join(u,v)然后把v splay到树根再打个标记就好. 至于子树操作...以后有空的话再学(咕咕咕警告) #include<bi ...

  7. 【刷题】洛谷 P3690 【模板】Link Cut Tree (动态树)

    题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor ...

  8. P3690 【模板】Link Cut Tree (动态树)

    P3690 [模板]Link Cut Tree (动态树) 认父不认子的lct 注意:不 要 把 $fa[x]$和$nrt(x)$ 混 在 一 起 ! #include<cstdio> v ...

  9. LuoguP3690 【模板】Link Cut Tree (动态树) LCT模板

    P3690 [模板]Link Cut Tree (动态树) 题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两 ...

随机推荐

  1. Canvas入门04-绘制矩形

    使用的API: ctx.strokeRect(x, y, width, height) 给一个矩形描边 ctx.fillRect(x, y, width, height) 填充一个矩形 ctx.cle ...

  2. 使用screen管理后台程序

    我们常需要SSH 或者telent 远程登录到Linux 服务器,经常运行一些需要很长时间才能完成的任务,在此期间不能关掉窗口或者断开连接,否则这个任务就会被杀掉,一切半途而废了.这时,我们可以用sc ...

  3. Zabbix-常见问题解决

    1.创建图形后字符乱码 # cd /usr/share/zabbix/fonts将Windows里面的 windows 控制面板——>字体——>如选择 “黑体”——>上传到当前目录# ...

  4. Java数据结构之递归(Recursion)

    1. 递归解决问题 各种数学问题如:8皇后问题,汉诺塔,阶乘问题,迷宫问题,球和篮子的问题(google编程大赛) 各种算法中也会使用到递归,比如快速排序,归并排序,二分查找,分治算法等 将用栈解决的 ...

  5. Linear Discriminant Analysis

    Suppose that we model each class density as multivariate Gaussian, in practice we do not know the pa ...

  6. 打印Java main参数

    public class Main { public static void main(String args[]){ System.out.println("打印main方法中的输入参数, ...

  7. 各类无次数限制的免费API接口,再也不怕找不到免费API了

    各类无次数限制的免费API接口整理,主要是聚合数据上和API Store上的一些,还有一些其他的. 聚合数据提供30大类,160种以上基础数据API服务,国内最大的基础数据API服务,下面就罗列一些免 ...

  8. 简单的物流项目实战,WPF的MVVM设计模式(四)

    接下来写ViewModels 创建运单的ViewModel类 public class CreateExpressWindowViewModel: NotificationObject { priva ...

  9. 拼接HTML代码在UIWebVIew中显示

    其原理:通过网络请求获得相关的信息,再通过手机端进行拼HTML,然后在WebView进行展示,此处还对文章中的图片增加点击效果,可以保存到相册中:文章的样式已经存在项目中,直接去调用: 1:首先了解两 ...

  10. Kafka在windows下的配置使用

    Kafka是最初由Linkedin公司开发,是一个分布式.支持分区的(partition).多副本的(replica),基于zookeeper协调的分布式消息系统,它的最大的特性就是可以实时的处理大量 ...