分析

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

一个点出发感染到根结点所花费的时间是路径上虚边的条数+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. Eclipse."Courier New"字体

    1.Win 7 下eclipse添加Courier New字体 - 彦帅的博客.html(https://blog.csdn.net/theblackbeard/article/details/525 ...

  2. .net core 学习小结之 PostMan报415

    首先415的官方解释是:对于当前请求的方法和所请求的资源,请求中提交的实体并不是服务器中所支持的格式,因此请求被拒绝. 也就是说我所准备的数据格式并不是后台代码使用的数据格式 后台代码如下 using ...

  3. 20191128 Spring Boot官方文档学习(9.10)

    9.10.数据库初始化 可以使用不同的方式初始化SQL数据库,具体取决于堆栈是什么.当然,如果数据库是一个单独的进程,您也可以手动执行.建议使用单一机制进行模式生成. 9.10.1.使用JPA初始化数 ...

  4. 使用Dockerfile制作镜像

    组成部分 基础镜像信息       FROM 维护者信息    MAINTAINER.LABEL 镜像操作指令       RUN.COPY.ADD.EXPOSE.WORKDIR.ONBUILD.US ...

  5. Linux/Unix下pid文件作用浅析

    转载:http://blog.csdn.net/changli_90/article/details/8911191 在Linux系统的目录/var/run下面一般我们都会看到很多的*.pid文件.而 ...

  6. 分布式事务解决方案汇总:2PC、3PC、消息中间件、TCC、状态机+重试+幂等(转)

    数据一致性问题非常多样,下面举一些常见例子.比如在更新数据的时候,先更新了数据库,后更新了缓存,一旦缓存更新失败,此时数据库和缓存数据会不一致.反过来,如果先更新缓存,再更新数据库,一旦缓存更新成功, ...

  7. MongoDB的使用学习之(六)MongoDB的高级查询之条件操作符

    此文分为两点,主要是在第二点--java 语法,但是按顺序必须先把原生态的语法写出来 (还有一篇文章也是不错的:MongoDB高级查询用法大全(包含MongoDB命令语法和Java语法,其实就是我整理 ...

  8. iOS APP 国际化

    pp Store 中很多流行的应用程序有多种语言版本.虽然这些应用程序可能因为很多因素而变得流行,但是具有多种本地化版本,肯定是其中一个因素.越多的人可以理解并使用您的应用程序,潜在的买家也就越多. ...

  9. WPS专业版及序列号

    目录 1. 软件下载 2. 序列号(永久) 1. 软件下载 城通网盘:https://sn9.us/dir/13403389-35833830-3fc98f (仅Android版) 官网: https ...

  10. 网络流最大流dinic

    hdu 6214 #include <bits/stdc++.h> #include<cstdio> #include<cstring> #include<q ...