bzoj 3779: 重组病毒【LCT+线段树维护dfs序】
%.8lf会WA!!%.8lf会WA!!%.8lf会WA!!要%.10lf!!
和4817有点像,但是更复杂。
首先对于操作一“在编号为x的计算机中植入病毒的一个新变种,在植入一个新变种时,病毒会在局域网中搜索核心计算机的位置,并沿着网络中最短的路径感染过去”,长得是不是有点像LCT中的access操作?进而发现,如果把同一颜色的点连起来作为LCT中的重边的话,那么询问二就相当于问路径上的虚边有多少。
假设没有换根操作,那么第二、三个操作是可以用树剖在线段树上维护的。 设每个点的权值val为这个点到根的路径上颜色个数,也就是虚边个数。那么考虑access操作的影响,对于他断开的重边,所在子树加一,对于他连上的重边,所在子树减一。直接在access过程中处理即可。
那么现在考虑换根操作:
首先出题人非常贴心的在换根操作后加了一个access,更加符合LCT的操作方式虽然不加应该就做不了了
首先对1为根进行dfs,把dfs序摊到线段树上,在这个线段树上维护修改和查询。
然后把平均数改成区间和,查完之后直接除即可(注意会爆int,注意精度问题)。
那么对于当先换根换到的root和要查询的子树x,用dfs序判断有三种情况:
- \( root=x \),相当于求全区间和,直接返回即可;
- x在root的子树中,那么换根对它没有影响,直接当做没有换根来查询即可;
- x不在root的子树中,那么答案为全区间和减去x下面root所在的子树的区间和。
#include<iostream>
#include<cstdio>
using namespace std;
const int N=300005;
int n,m,h[N],cnt,fa[N],de[N],fr[N],ed[N],id[N],dfn,rl[N],root=1,s[N],top;
char c[10];
struct qwe
{
int ne,to;
}e[N<<1];
struct xianduanshu
{
int l,r;
long long sum,lz;
}q[N<<2];
struct pinghengshu
{
int f,c[2],tg;
}t[N];
int read()
{
int r=0,f=1;
char p=getchar();
while(p>'9'||p<'0')
{
if(p==-1)
f=-1;
p=getchar();
}
while(p>='0'&&p<='9')
{
r=r*10+p-48;
p=getchar();
}
return r*f;
}
void add(int u,int v)
{
cnt++;
e[cnt].ne=h[u];
e[cnt].to=v;
h[u]=cnt;
}
void build(int ro,int l,int r)
{
q[ro].l=l,q[ro].r=r;
if(l==r)
return;
int mid=(l+r)>>1;
build(ro<<1,l,mid);
build(ro<<1|1,mid+1,r);
}
void pd(int ro)
{
q[ro<<1].sum+=q[ro].lz*(q[ro<<1].r-q[ro<<1].l+1);
q[ro<<1].lz+=q[ro].lz;
q[ro<<1|1].sum+=q[ro].lz*(q[ro<<1|1].r-q[ro<<1|1].l+1);
q[ro<<1|1].lz+=q[ro].lz;
q[ro].lz=0;
}
void update(int ro,int l,int r,int v)
{//cout<<l<<" "<<r<<" "<<v<<endl;
if(l>r)
return;
if(q[ro].l==l&&q[ro].r==r)
{
q[ro].sum+=v*(q[ro].r-q[ro].l+1);
q[ro].lz+=v;
return;
}
if(q[ro].lz)
pd(ro);
int mid=(q[ro].l+q[ro].r)>>1;
if(r<=mid)
update(ro<<1,l,r,v);
else if(l>mid)
update(ro<<1|1,l,r,v);
else
{
update(ro<<1,l,mid,v);
update(ro<<1|1,mid+1,r,v);
}
q[ro].sum=q[ro<<1].sum+q[ro<<1|1].sum;
}
long long ques(int ro,int l,int r)
{
if(l>r)
return 0;
if(q[ro].l==l&&q[ro].r==r)
return q[ro].sum;
if(q[ro].lz)
pd(ro);
int mid=(q[ro].l+q[ro].r)>>1;
if(r<=mid)
return ques(ro<<1,l,r);
else if(l>mid)
return ques(ro<<1|1,l,r);
else
return ques(ro<<1,l,mid)+ques(ro<<1|1,mid+1,r);
}
void dfs(int u,int fat)
{
t[u].f=fa[u]=fat;
de[u]=de[fat]+1;
fr[u]=++dfn;
update(1,fr[u],fr[u],de[u]);
for(int i=h[u];i;i=e[i].ne)
if(e[i].to!=fat)
dfs(e[i].to,u);
ed[u]=dfn;
}
bool srt(int x)
{
return t[t[x].f].c[0]!=x&&t[t[x].f].c[1]!=x;
}
void pud(int x)
{
if(t[x].tg)
{
t[x].tg=0;
t[t[x].c[0]].tg^=1;
t[t[x].c[1]].tg^=1;
swap(t[x].c[0],t[x].c[1]);
}
}
void zhuan(int x)
{
int l,r,y=t[x].f,z=t[y].f;
if(t[y].c[0]==x)
l=0;
else
l=1;
r=l^1;
if(!srt(y))
{
if(t[z].c[0]==y)
t[z].c[0]=x;
else
t[z].c[1]=x;
}
t[x].f=z;t[y].f=x;
t[t[x].c[r]].f=y;
t[y].c[l]=t[x].c[r];
t[x].c[r]=y;
}
void splay(int x)
{//cout<<"splay"<<x<<endl;
top=0;
s[++top]=x;
for(int i=x;!srt(i);i=t[i].f)
s[++top]=t[i].f;
while(top)
pud(s[top--]);
while(!srt(x))
{
int y=t[x].f,z=t[y].f;
if(!srt(y))
{
if((t[y].c[0]==x)^(t[z].c[0]==y))
zhuan(x);
else
zhuan(y);
}
zhuan(x);
}
}
int zhao(int x,int y)
{
for(int i=h[x];i;i=e[i].ne)
if(e[i].to!=fa[x]&&fr[y]>=fr[e[i].to]&&ed[y]<=ed[e[i].to])
return e[i].to;
return 0;
}
void jia(int x,int w)
{
if(x==root)
update(1,1,n,w);
else if(fr[root]>=fr[x]&&ed[root]<=ed[x])
{
int zi=zhao(x,root);
update(1,1,fr[zi]-1,w);
update(1,ed[zi]+1,n,w);
}
else
update(1,fr[x],ed[x],w);
}
int wk(int x)
{
pud(x);
while(t[x].c[0])
x=t[x].c[0],pud(x);
return x;
}
void acc(int x)
{
for(int i=0;x;i=x,x=t[x].f)
{
splay(x);
if(t[x].c[1])
jia(wk(t[x].c[1]),1);
t[x].c[1]=i;
if(t[x].c[1])
jia(wk(t[x].c[1]),-1);
}
}
void mkrt(int x)
{
acc(x);
splay(x);
root=x;
t[x].tg^=1;
}
double wen(int x)
{//cout<<ques(1,id[x],id[x]+si[x]-1)<<endl;
if(x==root)
return (double)ques(1,1,n)/n;
if(fr[root]>=fr[x]&&ed[root]<=ed[x])
{
int zi=zhao(x,root);
return (double)(ques(1,1,fr[zi]-1)+ques(1,ed[zi]+1,n))/(n-(ed[zi]-fr[zi]+1));
}
return (double)ques(1,fr[x],ed[x])/(ed[x]-fr[x]+1);
}
int main()
{
n=read(),m=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read();
add(x,y);add(y,x);
}
build(1,1,n);
dfs(1,0);
for(int i=2;i<=n;i++)
t[i].f=fa[i];
while(m--)
{
scanf("%s",c);
if(c[2]=='L')
{
int x=read();
acc(x);
}
else if(c[2]=='C')
{
int x=read();
mkrt(x);
}
else
{
int x=read();
printf("%.10lf\n",wen(x));
}
}
return 0;
}
bzoj 3779: 重组病毒【LCT+线段树维护dfs序】的更多相关文章
- BZOJ 3779 重组病毒 ——LCT 线段树
发现操作一很像一个LCT的access的操作. 然后答案就是路径上的虚边的数量. 然后考虑维护每一个点到根节点虚边的数量, 每次断开一条偏爱路径的时候,子树的值全部+1, 连接一条偏爱路径的时候,子树 ...
- BZOJ 3779 重组病毒 LCT+线段树(维护DFS序)
原题干(由于是权限题我就直接砸出原题干了,要看题意概述的话在下面): Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力 ...
- bzoj 3779: 重组病毒 LCT+线段树+倍增
题目: 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒. 实验在一个封闭 ...
- BZOJ 4817 [SDOI2017]树点涂色 (LCT+线段树维护dfs序)
题目大意:略 涂色方式明显符合$LCT$里$access$操作的性质,相同颜色的节点在一条深度递增的链上 用$LCT$维护一个树上集合就好 因为它维护了树上集合,所以它别的啥都干不了了 发现树是静态的 ...
- CF877E Danil and a Part-time Job 线段树维护dfs序
\(\color{#0066ff}{题目描述}\) 有一棵 n 个点的树,根结点为 1 号点,每个点的权值都是 1 或 0 共有 m 次操作,操作分为两种 get 询问一个点 x 的子树里有多少个 1 ...
- bzoj 3779 重组病毒 —— LCT+树状数组(区间修改+区间查询)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3779 RELEASE操作可以对应LCT的 access,RECENTER则是 makeroo ...
- P3703 [SDOI2017]树点涂色 LCT维护颜色+线段树维护dfs序+倍增LCA
\(\color{#0066ff}{ 题目描述 }\) Bob有一棵\(n\)个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点 ...
- CodeForces 343D 线段树维护dfs序
给定一棵树,初始时树为空 操作1,往某个结点注水,那么该结点的子树都注满了水 操作2,将某个结点的水放空,那么该结点的父亲的水也就放空了 操作3,询问某个点是否有水 我们将树进行dfs, 生成in[u ...
- bzoj 3779 重组病毒——LCT维护子树信息
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3779 调了很久……已经懒得写题解了.https://www.cnblogs.com/Zinn ...
随机推荐
- 洛谷—— P3372 【模板】线段树 1
P3372 [模板]线段树 1 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别 ...
- jmeter的线程组执行顺序不以其出现的顺序发生变化
jmeter可以同时配置多个线程组,那么他们的执行顺序是什么呢?和他们出现的顺序有什么关系呢? 先说下几个特殊的线程组:tearDown线程组和setUp线程组,tearDown线程组一定在最后执行, ...
- 浅谈python中的“ ==” 与“ is”、还有cmp
总之,比较内容相等使用 ‘==’ 1.is" 是用来比较 a 和 b 是不是指向同一个内存单元,而"=="是用来比较 a 和 b指向的内存单元中的值是不是相等 2.pyt ...
- Android - 渠道号(vender)
渠道号(vender) 本文地址: http://blog.csdn.net/caroline_wendy Android的apk公布,须要统计各个渠道(vendor)的激活数.就能够使用vendor ...
- swift-for循环遍历,遍历字典,循环生成数组
// Playground - noun: a place where people can play import UIKit //--------------------------------- ...
- eclipse Alt+/ 不能提示
普通情况下alt+/有代码提示作用,还有代码提示的快捷代码也不是alt+/,因此要恢复代码提示用alt+/.须要做两件事. 在 Window - Preferences - General - Ke ...
- libevent API 介绍
基本应用场景也是使用 libevnet 的基本流程,下面来考虑一个最简单的场景,使用livevent 设置定时器,应用程序只需要执行下面几个简单的步骤即可. 1)首先初始化 libevent 库,并保 ...
- ubuntu下打开eclipse·发现没有顶尖菜单项
在安装eclipse时,打开集成开发环境后没有菜单项. 网上些人说要写个shell脚步,感觉有点麻烦,其实就是少了一个环境变量 BUNTU_MENUPROXY. 在/etc/profile 里面新建这 ...
- 鸡肋的JdbcRDD
今天准备将mysql的数据倒腾到RDD.非常早曾经就知道有一个JdbcRDD.就想着使用一下,结果发现却是鸡肋一个. 首先,看看JdbcRDD的定义: * An RDD tha ...
- Java 中 泛型的限定
泛型 一般 出如今集合中,迭代器中 也会出现! 泛型 是为了 提高代码的 安全性. 泛型 确保数据类型的唯一性. 在我们经常使用的容器中. 越是 单一 约优点理啊! ...