http://www.lydsy.com/JudgeOnline/problem.php?id=3779

有一棵树,初始每个节点有不同的颜色

操作1:根节点到x的路径上的点 染上一种没有出现过的颜色

操作2:操作1后把x换成根

操作3:定义点x的点权为x到根节点路径上不同颜色的数量,查询x的子树点权和

LCT+线段树+dfs序

dfs一遍得到每个点的dfs序,

以及每个点子树的dfs序范围,记点x的子树dfs序范围为 [Lx,Rx]

线段树以dfs序为顺序维护

操作1就是access,

一条Preferred Path 上所有点的颜色相同

在轻重链交换的时候才会涉及到点权的修改

如果lct上父节点x和子节点y之间的边由重链变轻链,那么lct上 以子节点y为根的子树的所有点 的点权减1

实现就是找到t的Auxiliary Tree 上深度最小的点z, 区间[Lz,Rz] 减1

如果lct上父节点x和子节点y之间的边由轻链变重链,那么lct上 以子节点y为根的子树的所有点 的点权加1

实现就是找到t的Auxiliary Tree 上深度最小的点z, 区间[Lz,Rz] 加1

操作2就是LCT的换根操作

不用刻意的去维护换根对线段树的影响,因为换根之前会执行操作1,access

点到新的根节点路径上的颜色数量 就等于 点到原来根节点路径上的颜色数量

查询操作:

分析点x和根节点root 子树的包含关系

若x==root,那就是查询整棵树

若x在root的子树内,直接查x的子树

若root在x的子树内,设root在x的子节点p的子树内,那就是查询整棵树除去p的子树的部分

查询子树就是 线段树按dfs序维护的一段连续的区间

#include<cmath>
#include<cstdio>
#include<iostream> #define N 100001 using namespace std; typedef long long LL; int n;
int front[N],to[N<<],nxt[N<<],tot; int id[N],dy[N],lst[N],tim;
int dep[N];
int lim,F[N][]; int fa[N],ch[N][],root;
bool rev[N]; LL sum[N<<];
int siz[N<<],tag[N<<]; int st[N],top; void read(int &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
} void add(int u,int v)
{
to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
} void dfs(int x)
{
id[x]=++tim;
dy[tim]=x;
for(int i=front[x];i;i=nxt[i])
if(to[i]!=fa[x])
{
dep[to[i]]=dep[x]+;
F[to[i]][]=x;
fa[to[i]]=x;
dfs(to[i]);
}
lst[x]=tim;
} void build(int k,int l,int r)
{
siz[k]=r-l+;
if(l==r)
{
sum[k]=dep[dy[l]];
return;
}
int mid=l+r>>;
build(k<<,l,mid);
build(k<<|,mid+,r);
sum[k]=sum[k<<]+sum[k<<|];
} void tagging(int k,int w)
{
sum[k]+=w*siz[k];
tag[k]+=w;
} void push_down(int k)
{
tagging(k<<,tag[k]);
tagging(k<<|,tag[k]);
tag[k]=;
} void change(int k,int l,int r,int opl,int opr,int w)
{
if(l>=opl && r<=opr)
{
tagging(k,w);
return;
}
if(tag[k]) push_down(k);
int mid=l+r>>;
if(opl<=mid) change(k<<,l,mid,opl,opr,w);
if(opr>mid) change(k<<|,mid+,r,opl,opr,w);
sum[k]=sum[k<<]+sum[k<<|];
} void Change(int x,int w)
{
if(x==root) change(,,n,,n,w);
else if(id[root]>id[x] && id[root]<=lst[x])
{
int t=root,c=dep[root]-dep[x]-;
for(int i=lim;i>=;--i)
if(c&(<<i)) t=F[t][i];
if(id[t]>) change(,,n,,id[t]-,w);
if(lst[t]<n) change(,,n,lst[t]+,n,w);
}
else change(,,n,id[x],lst[x],w);
} LL query(int k,int l,int r,int opl,int opr)
{
if(l==opl && r==opr) return sum[k];
if(tag[k]) push_down(k);
int mid=l+r>>; LL res=;
if(opl<=mid) res+=query(k<<,l,mid,opl,min(mid,opr));
if(opr>mid) res+=query(k<<|,mid+,r,max(mid+,opl),opr);
return res;
} double Query(int x)
{
if(x==root) return 1.0*query(,,n,,n)/n;
else if(id[root]>id[x] && id[root]<=lst[x])
{
int t=root,c=dep[root]-dep[x]-;
for(int i=lim;i>=;--i)
if(c&(<<i)) t=F[t][i];
int siz=id[t]-+n-lst[t];
LL res=;
if(id[t]>) res+=query(,,n,,id[t]-);
if(lst[t]<n) res+=query(,,n,lst[t]+,n);
return 1.0*res/siz;
}
return 1.0*query(,,n,id[x],lst[x])/(lst[x]-id[x]+);
} void down(int x)
{
rev[x]^=;
if(ch[x][]) rev[ch[x][]]^=;
if(ch[x][]) rev[ch[x][]]^=;
std::swap(ch[x][],ch[x][]);
} bool isroot(int x)
{
return ch[fa[x]][]!=x && ch[fa[x]][]!=x;
} bool getson(int x)
{
return ch[fa[x]][]==x;
} void rotate(int x)
{
int y=fa[x],z=fa[y];
bool k=ch[y][]==x;
if(!isroot(y)) ch[z][ch[z][]==y]=x;
ch[y][k]=ch[x][k^]; ch[x][k^]=y;
fa[y]=x; fa[x]=z; fa[ch[y][k]]=y;
} void splay(int x)
{
st[top=]=x;
for(int i=x;!isroot(i);i=fa[i]) st[++top]=fa[i];
for(int i=top;i;--i)
if(rev[st[i]]) down(st[i]);
int y;
while(!isroot(x))
{
y=fa[x];
if(!isroot(y)) rotate(getson(x)==getson(y) ? y : x);
rotate(x);
}
} int find_root(int x)
{
if(rev[x]) down(x);
while(ch[x][])
{
x=ch[x][];
if(rev[x]) down(x);
}
return x;
} void access(int x)
{
int t=;
while(x)
{
splay(x);
if(ch[x][]) Change(find_root(ch[x][]),);
ch[x][]=t;
if(t) Change(find_root(t),-);
t=x; x=fa[x];
}
} void maker_root(int x)
{
access(x);
splay(x);
rev[x]^=;
root=x;
} int main()
{
freopen("recompile.in", "r", stdin);
freopen("recompile.out", "w", stdout);
int m;
read(n); read(m);
int u,v;
for(int i=;i<n;++i)
{
read(u); read(v);
add(u,v);
}
dep[]=;
dfs();
lim=log(n)/log();
for(int j=;j<=lim;++j)
for(int i=;i<=n;++i)
F[i][j]=F[F[i][j-]][j-];
build(,,n);
root=;
char c[]; int x;
while(m--)
{
scanf("%s",c);
read(x);
if(c[]=='L') access(x);
else if(c[]=='C') maker_root(x);
else printf("%.10lf\n",Query(x));
}
}

bzoj千题计划274:bzoj3779: 重组病毒的更多相关文章

  1. bzoj千题计划300:bzoj4823: [Cqoi2017]老C的方块

    http://www.lydsy.com/JudgeOnline/problem.php?id=4823 讨厌的形状就是四联通图 且左右各连一个方块 那么破坏所有满足条件的四联通就好了 按上图方式染色 ...

  2. bzoj千题计划205:bzoj1966: [Ahoi2005]VIRUS 病毒检测

    http://www.lydsy.com/JudgeOnline/problem.php?id=1966 f[i][j] 表示s的前i个和t的前j个是否匹配 转移看代码 注意初始化: f[0][0]= ...

  3. bzoj千题计划196:bzoj4826: [Hnoi2017]影魔

    http://www.lydsy.com/JudgeOnline/problem.php?id=4826 吐槽一下bzoj这道题的排版是真丑... 我还是粘洛谷的题面吧... 提供p1的攻击力:i,j ...

  4. bzoj千题计划280:bzoj4592: [Shoi2015]脑洞治疗仪

    http://www.lydsy.com/JudgeOnline/problem.php?id=4592 注意操作1 先挖再补,就是补的范围可以包含挖的范围 SHOI2015 的题 略水啊(逃) #i ...

  5. bzoj千题计划177:bzoj1858: [Scoi2010]序列操作

    http://www.lydsy.com/JudgeOnline/problem.php?id=1858 2018 自己写的第1题,一遍过 ^_^ 元旦快乐 #include<cstdio> ...

  6. bzoj千题计划317:bzoj4650: [Noi2016]优秀的拆分(后缀数组+差分)

    https://www.lydsy.com/JudgeOnline/problem.php?id=4650 如果能够预处理出 suf[i] 以i结尾的形式为AA的子串个数 pre[i] 以i开头的形式 ...

  7. bzoj千题计划304:bzoj3676: [Apio2014]回文串(回文自动机)

    https://www.lydsy.com/JudgeOnline/problem.php?id=3676 回文自动机模板题 4年前的APIO如今竟沦为模板,,,╮(╯▽╰)╭,唉 #include& ...

  8. bzoj千题计划292:bzoj2244: [SDOI2011]拦截导弹

    http://www.lydsy.com/JudgeOnline/problem.php?id=2244 每枚导弹成功拦截的概率 = 包含它的最长上升子序列个数/最长上升子序列总个数 pre_len ...

  9. bzoj千题计划278:bzoj4590: [Shoi2015]自动刷题机

    http://www.lydsy.com/JudgeOnline/problem.php?id=4590 二分 这么道水题 没long long WA了两发,没判-1WA了一发,二分写错WA了一发 最 ...

随机推荐

  1. Bzoj3930: [CQOI 2015] 选数 & COGS2699: [CQOI 2015] 选数加强版

    题面 Bzoj COGS加强版 Sol 非加强版可以枚举AC这里不再讲述 设\(f(i)\)表示在\([L, H]\)取\(N\)个,\(gcd为i\)的方案数 \(F(i)=\sum_{i|d}f( ...

  2. js常见算法(一)

    1.每个单词手字母大写 var capitalizeEveryWord = str => str.replace(/\b[a-z]/g, char => char.toUpperCase( ...

  3. 关于LINUX各类系统资源整合

    在系统维护的过程中,随时可能有需要查看 CPU和内存的使用率,并根据相应信息分析系统状况的需求.本文介绍一下几种常见的Linux系统资源查看命令. 1.总体内存占用的查看 命令:free 图1 fre ...

  4. DaTaX当成jar包当作第三方库启动的相关问题

    上一篇已经大致的将了本地状况下DaTaX的纯Java代码启动的过程 http://www.cnblogs.com/blogsofmy/p/8287637.html不了解的请点超链接 这次我们来说说文件 ...

  5. Vuex 教程案例:计数器以及列表展示

    本案例github:https://github.com/axel10/Vuex_demo-Counter-and-list 本篇教程将以计数器及列表展示两个例子来讲解Vuex的简单用法. 从安装到启 ...

  6. 解决Win10下_findnext()异常

    在win10中,使用文件遍历函数_findnext会报0xC0000005错误 ,发生访问冲突错误 错误定位到ntdll.dll 原因: _findnext()第一个参数"路径句柄" ...

  7. 解析Visual C# 7.2中的private protected访问修饰符

    去年12月份,随着Visual Studio 2017 Update 15.5的发布,Visual C#迎来了它的最新版本:7.2. 在这个版本中,有个让人难以理解的新特性,就是private pro ...

  8. QT 创建一个具有复选功能的下拉列表控件

    最近研究了好多东西,前两天突然想做一个具有复选功能的下拉列表框.然后在网上"学习"了很久之后,终于发现了一个可以用的,特地发出来记录一下. 一.第一步肯定是先创建一个PROJECT ...

  9. 分享python分析wave, pcm音频文件

    最近研究的,我用的是python3.3, 用matplotlib画图, 下面代码演示分析pcm文件,如果是wave文件,把wave的文件头去掉就是pcm文件了. 代码如下 # -*- coding:u ...

  10. 搭建nuxtjs程序 —— 用户信息 or token怎么不丢失

    框架背景:开发框架采用vue,需要更好的SEO,更快的内容到达时间,从浏览器看不到对服务器的请求接口,选用开箱即用的nuxtjs. 问题背景:1. 前后分离,需前端存储token及登录后的用户信息: ...