bzoj 3779: 重组病毒
一道好题~~
一个点到根传染需要的时间是这段路径上不同颜色的数目,一个点子树到根平均传染时间就是加权平均数了(好像是废话)。
所以只要用线段树维护dfs序就这个可以了,换根的话一个点的子树要么在dfs序中不变,要么被截成了[1,l)和(r,n]两段(当这个点为当前root的祖先),l和r即为包含当前根的这个点的那个儿子的dfs序中的st和ed,只要分类讨论一下就可以了。
所以问题只剩什么时候在线段树上修改,我们发现1操作和LCT中的access操作很像,2操作就是make_root,每个splay就是一个相同的颜色段,那么一个点到根的距离就是LCT中虚边的个数,把虚边改实边子树-1,反过来子树+1,而LCT的复杂度是nlogn的,那直接做就好了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 100005
#define ll long long
using namespace std;
int head[N],nxt[N*],ver[N*],tot;int n,m;
void addd(int a,int b)
{
tot++;nxt[tot]=head[a];head[a]=tot;ver[tot]=b;return ;
}
int rev[N],ch[N][],root,L[N],R[N],fa[N],faa[N];
bool isroot(int x)
{
return ch[fa[x]][]!=x&&ch[fa[x]][]!=x;
}
void push_down(int x)
{
if(rev[x])
{
rev[x]^=;rev[ch[x][]]^=;rev[ch[x][]]^=;
swap(L[ch[x][]],R[ch[x][]]);
swap(L[ch[x][]],R[ch[x][]]);
swap(ch[x][],ch[x][]);
}
return ;
}
void push_up(int x)
{
if(!ch[x][])L[x]=x;
else L[x]=L[ch[x][]];
if(!ch[x][])R[x]=x;
else R[x]=R[ch[x][]];
}
void rotate(int p)
{
int q=fa[p],y=fa[q],x=(ch[q][]==p);
ch[q][x]=ch[p][x^];fa[ch[q][x]]=q;
ch[p][x^]=q;
fa[p]=y;
if(!isroot(q))
{
if(ch[y][]==q)ch[y][]=p;
else ch[y][]=p;
}
fa[q]=p;
push_up(q);
}
int q[N],topp;
void splay(int x)
{
q[++topp]=x;
for(int i=x;!isroot(i);i=fa[i])q[++topp]=fa[i];
while(topp)push_down(q[topp--]);
for(int y;!isroot(x);rotate(x))
{
y=fa[x];
if(!isroot(y))
{
if((ch[fa[y]][]==y)^(ch[y][]==x))rotate(x);
else rotate(y);
}
}
push_up(x);
}
struct node
{
ll lazy,sum;
}a[N*];
int sz[N];
int st[N],ed[N],z,jian[N],dep[N],top[N],son[N];
int find(int x,int y)
{
while(top[y]!=top[x])
{
if(faa[top[y]]==x)return top[y];
y=faa[top[y]];
}
return son[x];
}
void dfs(int x,int f)
{
st[x]=++z;jian[z]=dep[x];sz[x]=;L[x]=R[x]=x;
for(int i=head[x];i;i=nxt[i])
{
if(ver[i]==f)continue;
fa[ver[i]]=x;dep[ver[i]]=dep[x]+;faa[ver[i]]=x; dfs(ver[i],x);
sz[x]+=sz[ver[i]];
if(sz[ver[i]]>sz[son[x]])son[x]=ver[i];
}
ed[x]=z;
return ;
}
void dffs(int x,int f,int tp)
{
top[x]=tp;
if(son[x])dffs(son[x],x,tp);
for(int i=head[x];i;i=nxt[i])
{
if(ver[i]==f||ver[i]==son[x])continue;
dffs(ver[i],x,ver[i]);
}
}
void pd(int x,int l,int mid,int r)
{
if(a[x].lazy)
{
a[x*].sum+=a[x].lazy*(mid-l+);
a[x*+].sum+=a[x].lazy*(r-mid);
a[x*].lazy+=a[x].lazy;a[x*+].lazy+=a[x].lazy;
a[x].lazy=;
}return ;
}
ll qur(int x,int l,int r,int lll,int rr)
{
if(rr<lll)return ;
if(lll<=l&&rr>=r)
{
return a[x].sum;
}
int mid=(l+r)>>;
pd(x,l,mid,r);
if(lll>mid)return qur(x*+,mid+,r,lll,rr);
if(rr<=mid)return qur(x*,l,mid,lll,rr);
return qur(x*,l,mid,lll,rr)+qur(x*+,mid+,r,lll,rr);
}
void add(int x,int l,int r,int lll,int rr,ll z)
{
if(rr<lll)return ;
if(lll<=l&&rr>=r)
{
a[x].sum+=z*(r-l+);
a[x].lazy+=z;
return ;
}
int mid=(l+r)>>;
pd(x,l,mid,r);
if(lll<=mid)add(x*,l,mid,lll,rr,z);
if(rr>mid)add(x*+,mid+,r,lll,rr,z);
a[x].sum=a[x*].sum+a[x*+].sum;
}
void build(int x,int l,int r)
{
if(l==r)
{
a[x].sum=jian[l];
return ;
}
int mid=(l+r)>>;
build(x*,l,mid);build(x*+,mid+,r);
a[x].sum=a[x*].sum+a[x*+].sum;
return ;
}
void gao(int x,int z)
{
if(x==root)
{
add(,,n,,n,z);
}
else if(st[x]<st[root]&&ed[x]>=ed[root])
{
int t=find(x,root);
add(,,n,,st[t]-,z);
add(,,n,ed[t]+,n,z);
}
else
{
add(,,n,st[x],ed[x],z);
}
}
void access(int x)
{
for(int t=;x;t=x,x=fa[x])
{
splay(x);
if(t)gao(L[t],-);
if(ch[x][])
{
gao(L[ch[x][]],);
}
ch[x][]=t;
push_up(x);
}
return ;
}
void make_root(int x)
{
access(x);splay(x);
rev[x]^=;swap(L[x],R[x]);
return ;
}
int qursize(int x)
{
if(x==root)return n;
if(st[x]<st[root]&&ed[x]>=ed[root])
{
int t=find(x,root);
return n-sz[t];
}
else return sz[x];
}
ll qurs(int x)
{
if(x==root)return qur(,,n,,n);
if(st[x]<st[root]&&ed[x]>=ed[root])
{
int t=find(x,root);
return qur(,,n,,st[t]-)+qur(,,n,ed[t]+,n);
}
return qur(,,n,st[x],ed[x]);
}
int main()
{
scanf("%d%d",&n,&m);
int t1,t2;
for(int i=;i<n;i++)
{
scanf("%d%d",&t1,&t2);
addd(t1,t2);addd(t2,t1);
}
dep[]=;
dfs(,-);
build(,,n);
dffs(,-,);
char c[];root=;int tmp;
for(int i=;i<=m;i++)
{
scanf("%s",c+);
scanf("%d",&tmp);
if(c[]=='Q')
{
int size=qursize(tmp);
ll ss=qurs(tmp);
printf("%.10lf\n",((double)ss)/size);
}
else if(c[]=='L')
{
access(tmp); }
else
{
make_root(tmp);
root=tmp;
}
}
return ;
}
bzoj 3779: 重组病毒的更多相关文章
- bzoj 3779: 重组病毒 LCT+线段树+倍增
题目: 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒. 实验在一个封闭 ...
- BZOJ 3779: 重组病毒(线段树+lct+树剖)
题面 escription 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病 ...
- BZOJ 3779 重组病毒 LCT+线段树(维护DFS序)
原题干(由于是权限题我就直接砸出原题干了,要看题意概述的话在下面): Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力 ...
- bzoj 3779 重组病毒——LCT维护子树信息
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3779 调了很久……已经懒得写题解了.https://www.cnblogs.com/Zinn ...
- bzoj 3779 重组病毒 —— LCT+树状数组(区间修改+区间查询)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3779 RELEASE操作可以对应LCT的 access,RECENTER则是 makeroo ...
- bzoj 3779: 重组病毒【LCT+线段树维护dfs序】
%.8lf会WA!!%.8lf会WA!!%.8lf会WA!!要%.10lf!! 和4817有点像,但是更复杂. 首先对于操作一"在编号为x的计算机中植入病毒的一个新变种,在植入一个新变种时, ...
- bzoj 3779 重组病毒 好题 LCT+dfn序+线段树分类讨论
题目大意 1.将x到当前根路径上的所有点染成一种新的颜色: 2.将x到当前根路径上的所有点染成一种新的颜色,并且把这个点设为新的根: 3.查询以x为根的子树中所有点权值的平均值. 分析 原题codec ...
- BZOJ 3779 重组病毒 ——LCT 线段树
发现操作一很像一个LCT的access的操作. 然后答案就是路径上的虚边的数量. 然后考虑维护每一个点到根节点虚边的数量, 每次断开一条偏爱路径的时候,子树的值全部+1, 连接一条偏爱路径的时候,子树 ...
- 【BZOJ】3779 重组病毒
[算法]Link-Cut Tree+线段树(维护DFS序) [题解]整整三天……T_T 这篇题解比较资瓷:permui 这道题虽然树形态没有变化,但用lct写的原因在于把题目中的操作一进行了神转化:每 ...
随机推荐
- prometheus-operator 监控 Rabbitmq集群
首先我们监控服务需要知道prometheus-operator是如何去工作的,才好去写相关的yaml配置,这里我划分成了5个部分,如果容器服务本身就以k8s来编排的,那就只需要三步,这里因为我的rab ...
- Linux 磁盘与文件系统(EXT2)简介
Linux 中,一切(或几乎一切)都是文件. 一.Linux 磁盘分区与文件系统 1.1 磁盘分区 磁盘的分区主要分为主分区和扩展分区 1)主分区:总共最多只能有四个主分区: 2)扩展分区:只能有一个 ...
- kali vmtools 不能复制粘贴解决方法(绝对实用)
朋友问起怎么vm kali 2019怎么不能复制了,而且网上的方法大多不适合.我就在这儿记录一笔吧,方便大家. 之前发现最新kali复制粘贴不能用,后来发现一个奇妙的套路,不是共享文件夹.只需要把文件 ...
- 定时任务crone表达式demo
1. cron表达式格式: {秒数} {分钟} {小时} {日期} {月份} {星期} {年份(可为空)} 2. cron表达式各占位符解释: {秒数} ==> 允许值范围: 0~59 ,不允许 ...
- java分布式事务,及解决方案
1.什么是分布式事务 分布式事务就是指事务的参与者.支持事务的服务器.资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上.以上是百度百科的解释,简单的说,就是一次大的操作由不同的小操作组成 ...
- Vue 实例详解与生命周期
Vue 实例详解与生命周期 Vue 的实例是 Vue 框架的入口,其实也就是前端的 ViewModel,它包含了页面中的业务逻辑处理.数据模型等,当然它也有自己的一系列的生命周期的事件钩子,辅助我们进 ...
- 互评Beta版本 - Hello World团队项目空天猎
由于改组项目未提供可以直接进行安装运行的安装包或可执行文件,所以我找到了该组组长陈同学,由他根据其小组项目的功能说明书进行演示. 基于NABCD评论作品,及改进建议 每个小组评论其他小组beta发布的 ...
- android随机运算器开发小结1
想到第一天自己写了一个简单的四则运算程序的情景:我便想起了引起我们不断迭代开发的程序背景是:二柱子接受老师安排的给孩子出题的任务,每次需要给孩子设置出题任务,生成相应的小学运算题目,所以我们面对的需求 ...
- css3学习笔记一
首先界面是二维的但也可以有三维的效果.先了解浏览器兼容性问题,火狐加前缀(-moz-)IE加(-MF-)谷歌加(-webkit),简单介绍css3的几个属性. 对于背景来说如果是单纯着一种颜色可以会单 ...
- java小学生四则运算带面板版 但我不知道为什么同类变量却进不了动作监听中去
---恢复内容开始--- package yun; import java.util.*; import java.awt.*; import java.awt.event.ActionEvent; ...