题目大意

1、将x到当前根路径上的所有点染成一种新的颜色;

2、将x到当前根路径上的所有点染成一种新的颜色,并且把这个点设为新的根;

3、查询以x为根的子树中所有点权值的平均值。

分析

原题codechef ,Gangsters of Treeland

那题没有换根操作

用神转化把问题转操作1转化成access操作

操作3转化成每个点到根上有多少条虚边

用dfn序+线段树维护

现在多了个换根操作,只是线段树上加个分类讨论而已

注意

longdouble会Wa,double就A了

姿势

1.用dfn序判断x是否y的祖先

bool ispre(int x,int y){
if(x==y) return 0;//相等时不是祖先
return bg[x]<=bg[y]&&ed[y]<=ed[x];
}

2.分类讨论姿势

xxx(int x){
if(x==rt) xxx;
else if(ispre(x,rt)){
xxx;
}
else{
xxx;
}
}

3.多种数据结构时,用类似 seg_mdf()这样加前缀和下划线的方法

4.以后splay打翻转标记时就把儿子换了吧

5.可用注释分割代码

solution

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
typedef double db;
typedef long long LL;
const int M=100007; inline int rd(){
int x=0;bool f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-')f=0;
for(;isdigit(c);c=getchar()) x=x*10+c-48;
return f?x:-x;
} int n,m,rt;
int g[M],te; struct edge{
int y,nxt;
}e[M<<1]; void addedge(int x,int y){
e[++te].y=y;e[te].nxt=g[x];g[x]=te;
} //////////////////////////////// split tree int top[M],pre[M];
int bg[M],ed[M],tdfn;
int dep[M],sz[M];
int son[M],pid[M]; bool ispre(int x,int y){
if(x==y) return 0;//*************
return bg[x]<=bg[y]&&ed[y]<=ed[x];
} void dfs1(int x){
sz[x]=1;
int p,y;
for(p=g[x];p;p=e[p].nxt)
if((y=e[p].y)!=pre[x]){
pre[y]=x;
dep[y]=dep[x]+1;
dfs1(y);
sz[x]+=sz[y];
if(sz[y]>sz[son[x]]) son[x]=y;
}
} void dfs2(int x){
bg[x]=++tdfn;
pid[tdfn]=x;
if(son[x]){
top[son[x]]=top[x];
dfs2(son[x]);
}
int p,y;
for(p=g[x];p;p=e[p].nxt)
if((y=e[p].y)!=pre[x]&&y!=son[x]){
top[y]=y;
dfs2(y);
}
ed[x]=tdfn;
} int jump(int x,int to){
for(;dep[top[x]]>dep[to];x=pre[x]){
x=top[x];
if(pre[x]==to) return x;
}
return pid[bg[to]+1];
} LL getsz(int x){
if(x==rt) return n;
if(ispre(x,rt)){
int y=jump(rt,x);
return n-sz[y];
}
else{
return sz[x];
}
} ////////////////////////////////// Segment struct Seg{
LL sum,tag;
}c[M<<2]; void seg_pushup(int x){
c[x].sum=c[x<<1].sum+c[x<<1|1].sum;
} void seg_totag(int x,LL d,LL len){
c[x].sum+=d*len;
c[x].tag+=d;
} void seg_pushdown(int x,LL aa,LL bb){
if(c[x].tag){
seg_totag(x<<1,c[x].tag,aa);
seg_totag(x<<1|1,c[x].tag,bb);
c[x].tag=0;
}
} void seg_mdf(int x,int l,int r,int tl,int tr,LL d){
if(tl<=l&&r<=tr){
seg_totag(x,d,r-l+1);
return;
}
int mid=l+r>>1;
seg_pushdown(x,mid-l+1,r-mid);
if(tl<=mid) seg_mdf(x<<1,l,mid,tl,tr,d);
if(mid<tr) seg_mdf(x<<1|1,mid+1,r,tl,tr,d);
seg_pushup(x);
} void seg_add(int x,LL d){
if(x==rt) return seg_totag(1,d,tdfn);
if(ispre(x,rt)){
int y=jump(rt,x);
seg_mdf(1,1,tdfn,bg[1],ed[1],d);
seg_mdf(1,1,tdfn,bg[y],ed[y],-d);
}
else{
seg_mdf(1,1,tdfn,bg[x],ed[x],d);
}
} LL seg_get(int x,int l,int r,int tl,int tr){
if(tl<=l&&r<=tr) return c[x].sum;
int mid=l+r>>1;
seg_pushdown(x,mid-l+1,r-mid);
LL res=0;
if(tl<=mid) res+=seg_get(x<<1,l,mid,tl,tr);
if(mid<tr) res+=seg_get(x<<1|1,mid+1,r,tl,tr);
return res;
} LL seg_sum(int x){
if(x==rt) return c[1].sum;
LL res=0;
if(ispre(x,rt)){
int y=jump(rt,x);
res+=seg_get(1,1,tdfn,bg[1],ed[1]);
res-=seg_get(1,1,tdfn,bg[y],ed[y]);
}
else{
res=seg_get(1,1,tdfn,bg[x],ed[x]);
}
return res;
} /////////////////////////////////////// LCT struct LCT{
int ch[2],p,rev;
int id,lf,rt;//**********************************
void init(int ii){
ch[0]=ch[1]=p=rev=0;
lf=rt=id=ii;
}
}a[M]; int stack[M],tot; void torev(int x){
a[x].rev^=1;
swap(a[x].ch[0],a[x].ch[1]);//****
swap(a[x].lf,a[x].rt);
} void pushup(int x){
a[x].lf=a[x].rt=a[x].id;
if(a[x].ch[0]) a[x].lf=a[a[x].ch[0]].lf;
if(a[x].ch[1]) a[x].rt=a[a[x].ch[1]].rt;
} void pushdown(int x){
if(a[x].rev){
if(a[x].ch[0]) torev(a[x].ch[0]);
if(a[x].ch[1]) torev(a[x].ch[1]);
a[x].rev^=1;
}
} bool isrt(int x){
int y=a[x].p;
return a[y].ch[0]!=x&&a[y].ch[1]!=x;
} void clear(int x){
for(;!isrt(x);x=a[x].p) stack[++tot]=x;
for(stack[++tot]=x;tot>0;tot--) pushdown(stack[tot]);
} void rot(int x){
int y=a[x].p;
int z=a[y].p;
int D=a[y].ch[1]==x,ss=D^1;
if(!isrt(y)) a[z].ch[a[z].ch[1]==y]=x;
a[x].p=z;
a[y].p=x;
if(a[x].ch[ss]) a[a[x].ch[ss]].p=y;
a[y].ch[D]=a[x].ch[ss];
a[x].ch[ss]=y;
pushup(y);
pushup(x);
} void splay(int x){
int y,z;
for(clear(x);!isrt(x);rot(x)){
y=a[x].p;
z=a[y].p;
if(isrt(y)) continue;
if((a[y].ch[1]==x)!=(a[z].ch[1]==y)) rot(x);
else rot(y);
}
} void access(int x){
for(int t=0;x;t=x,x=a[x].p){
splay(x);
if(a[x].ch[1]) seg_add(a[a[x].ch[1]].lf,1);
if(t) seg_add(a[t].lf,-1);
a[x].ch[1]=t;
pushup(x);
}
} void ac(int x){
access(x);
splay(x);
} void chgrt(int x){
ac(x);
torev(x);
} ///////////////////////////// main int main(){
int i,x,y; n=rd(),m=rd();rt=1;
for(i=1;i<n;i++){
x=rd(),y=rd();
addedge(x,y);
addedge(y,x);
} pre[1]=0;
dep[1]=1;
dfs1(1);
top[1]=1;
dfs2(1); for(i=1;i<=n;i++){
a[i].init(i);
if(pre[i]){
a[i].p=pre[i];
seg_add(i,1);
}
} char s[13]; while(m--){
scanf("%s",s);
x=rd();
if(s[2]=='L'){
ac(x);
}
else if(s[2]=='C'){
chgrt(x);
rt=x;
}
else{
LL tp1=seg_sum(x);
LL tp2=getsz(x);
tp1+=tp2; printf("%.10lf\n",(db)tp1/(db)tp2);
}
} return 0;
}

bzoj 3779 重组病毒 好题 LCT+dfn序+线段树分类讨论的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

  7. bzoj 3779: 重组病毒

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

  8. BZOJ.4817.[SDOI2017]树点涂色(LCT DFS序 线段树)

    题目链接 操作\(1.2\)裸树剖,但是操作\(3\)每个点的答案\(val\)很不好维护.. 如果我们把同种颜色的点划分到同一连通块中,那么向根染色的过程就是Access()! 最初所有点间都是虚边 ...

  9. bzoj4817/luogu3703 树点涂色 (LCT+dfs序+线段树)

    我们发现,这个染色的操作他就很像LCT中access的操作(为什么??),然后就自然而然地想到,其实一个某条路径上的颜色数量,就是我们做一个只有access操作的LCT,这条路径经过的splay的数量 ...

随机推荐

  1. Python面向对象(三)

    类的使用:实例化.属性引用 实例化 g1 = Garen('草丛伦1') # 实例化 g2 = Garen('草丛伦2') g3 = Garen('草丛伦3') 类的属性:变量和函数 print(Ga ...

  2. Bootstrap历练实例:面板的标题

    面板标题 我们可以通过以下两种方式来添加面板标题: 使用 .panel-heading class 可以很简单地向面板添加标题容器.to easily add a heading container ...

  3. Java第11次作业:什么是继承?继承的好处?什么是覆写?super()?构造代码块?子父类初始化顺序? 抽象类能用final声明吗?final关键字声明类 方法 变量以及全局常量?抽象类的构造方法?

    什么是继承? 继承是以父类为基础,子类可以增加新的数据或新的功能.子类不能选择性地继承父类.这种技术使得复用以前的代码非常容易. JAVA不支持多继承,单继承使JAVA的继承关系很简单,一个类只能有一 ...

  4. Template 基础篇-函数模板(待看

    Template 基础篇-函数模板 Template所代表的泛型编程是C++语言中的重要的组成部分,我将通过几篇blog对这半年以来的学习做一个系统的总结,本文是基础篇的第一部分. Template ...

  5. NOIP模拟赛 水灾

    大雨应经下了几天雨,却还是没有停的样子.土豪CCY刚从外地赚完1e元回来,知道不久除了自己别墅,其他的地方都将会被洪水淹没. CCY所在的城市可以用一个N*M(N,M<=50)的地图表示,地图上 ...

  6. pandas中层次化索引与切片

    Pandas层次化索引 1. 创建多层索引 隐式索引: 常见的方式是给dataframe构造函数的index参数传递两个或是多个数组 Series也可以创建多层索引 Series多层索引 B =Ser ...

  7. 在VMware上安装centos7

    1. 下载centos7 64位镜像 linux官网下载:https://www.centos.org/download/ 2. 在VMware上安装centos7 2.1 新建虚拟机 打开虚拟机主页 ...

  8. HTTP-常用配置

    前言 这篇主要介绍HTTP服务程序环境 可能有一些介绍不到,博主能力有限,欢迎大神来纠正改进 HTTP协议从http/0.9到如今的http/2.0中间发生了很大的改变,现在主流的事http/1.1 ...

  9. Linux 用户管理切换用户su和提取命令sudo-visudu详解

    一.su --run a shell with substitute user and group IDs -,-l,--login make the shell a login shell, cle ...

  10. 科学计算库Numpy——numpy.ndarray

    创建ndarray 元素类型 对于ndarray结构来说,里面所有的元素必须是同一类型的,如果不是的话,会自动的向下进行转换. 元素类型所占字节数 数组维数 元素个数 数组的维度 数组中填充固定值 索 ...