BZOJ 3779: 重组病毒(线段树+lct+树剖)
题面
escription
黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒。这种病毒的繁殖和变异能力极强。为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒。
实验在一个封闭的局域网内进行。局域网内有n台计算机,编号为1~n。一些计算机之间通过网线直接相连,形成树形的结构。局域网中有一台特殊的计算机,称之为核心计算机。根据一些初步的研究,研究员们拟定了一个一共m步的实验。实验开始之前,核心计算机的编号为1,每台计算机中都有病毒的一个变种,而且每台计算机中的变种都不相同。实验中的每一步会是下面中的一种操作:
1、 RELEASE x
在编号为x的计算机中植入病毒的一个新变种。这个变种在植入之前不存在于局域网中。
2、 RECENTER x
将核心计算机改为编号为x的计算机。但是这个操作会导致原来核心计算机中的病毒产生新变种,并感染过来。换言之,假设操作前的核心计算机编号为y,相当于在操作后附加了一次RELEASE y的操作。
根据研究的结论,在植入一个新变种时,病毒会在局域网中搜索核心计算机的位置,并沿着网络中最短的路径感染过去。
而第一轮实验揭露了一个惊人的真相:病毒的不同变种是互斥的。新变种在感染一台已经被旧变种感染的电脑时,会把旧变种完全销毁之后再感染。但研究员发现了实现过程中的漏洞。如果新变种在感染过程中尚未销毁过这类旧变种,需要先花费1单位时间分析旧变种,才能销毁。如果之前销毁过这类旧变种,就可以认为销毁不花费时间。病毒在两台计算机之间的传播亦可认为不花费时间。
研究员对整个感染过程的耗时特别感兴趣,因为这是消灭病毒的最好时机。于是在m步实验之中,研究员有时还会做出如下的询问:
3、 REQUEST x
询问如果在编号为x的计算机的关键集合中的计算机中植入一个新变种,平均感染时间为多长。编号为y的计算机在编号为x的计算机的关键集合中,当且仅当从y沿网络中的最短路径感染到核心计算机必须经过x。由于有RECENTER操作的存在,这个集合并不一定是始终不变的。
至此,安全机构认为已经不需要实际的实验了,于是他们拜托你编写一个程序,模拟实验的结果,并回答所有的询问。
Input
输入的第一行包含两个整数n和m,分别代表局域网中计算机的数量,以及操作和询问的总数。
接下来n-1行,每行包含两个整数x和y,表示局域网中编号为x和y的计算机之间有网线直接相连。
接下来m行,每行包含一个操作或者询问,格式如问题描述中所述。
Output
对于每个询问,输出一个实数,代表平均感染时间。输出与答案的绝对误差不超过 10^(-6)时才会被视为正确。
Sample Input
8 6
1 2
1 3
2 8
3 4
3 5
3 6
4 7
REQUEST 7
RELEASE 3
REQUEST 3
RECENTER 5
RELEASE 2
REQUEST 1
Sample Output
4.0000000000
2.0000000000
1.3333333333
HINT
N < = 1 00 000 M < = 1 00 000
解题思路
数据结构恶心题。发现病毒的传播和\(lct\)的\(access\)很像,如果虚边变成实边就让这个边权变为\(0\),实边变成虚边就让这个边权变为\(1\),然后我们用线段树维护一下,线段树下标为\(dfs\)序。然后对于换根就直接\(makeroot\),对于询问要分类讨论一下。和\(BZOJ 3083\)很像。最后注意修改的时候要记录一下深度最浅的点,就是每个\(splay\)的根,从根进行修改。这题要\(long\) \(long\),多年\(oi\)一场空,不开\(long\) \(long\)见祖宗 ,写的时候见了祖宗了。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define int long long
using namespace std;
const int MAXN = 200005;
typedef long long LL;
inline int rd(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?x:-x;
}
int n,m,head[MAXN],cnt,to[MAXN<<1],nxt[MAXN<<1],ll[MAXN],rr[MAXN],Fa[MAXN];
int dep[MAXN],wt[MAXN],fa[MAXN],son[MAXN],top[MAXN];
int siz[MAXN],sum[MAXN<<2],lazy[MAXN<<2],in[MAXN],out[MAXN],rt,num;
bool tag[MAXN];
inline void add(int bg,int ed){
to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt;
}
void dfs1(int x,int f,int d){
dep[x]=d;fa[x]=f;siz[x]=1;ll[x]=rr[x]=x;
in[x]=++num;wt[num]=d;Fa[x]=f;
int maxson=-1,u;
for(int i=head[x];i;i=nxt[i]){
u=to[i];if(u==f) continue;
dfs1(u,x,d+1);siz[x]+=siz[u];
if(siz[u]>maxson) {maxson=siz[u];son[x]=u;}
}out[x]=num;
}
void dfs2(int x,int topf){
top[x]=topf;
if(!son[x]) return;dfs2(son[x],topf);int u;
for(int i=head[x];i;i=nxt[i]){
u=to[i];if(u==fa[x] || u==son[x]) continue;
dfs2(u,u);
}
}
void build(int x,int l,int r){
if(l==r){
sum[x]=wt[l];return ;
}
int mid=(l+r)>>1;build(x<<1,l,mid);build(x<<1|1,mid+1,r);
sum[x]=sum[x<<1]+sum[x<<1|1];
}
inline void pushdown(int x,int ln,int rn){
sum[x<<1]+=ln*lazy[x];sum[x<<1|1]+=rn*lazy[x];
lazy[x<<1]+=lazy[x];lazy[x<<1|1]+=lazy[x];lazy[x]=0;
}
inline void update(int x,int l,int r,int L,int R,int k){
if(R<L) return;
if(L<=l && r<=R) {
sum[x]+=(r-l+1)*k;lazy[x]+=k;return;
}
int mid=(l+r)>>1;if(lazy[x]) pushdown(x,mid-l+1,r-mid);
if(L<=mid) update(x<<1,l,mid,L,R,k);
if(mid<R) update(x<<1|1,mid+1,r,L,R,k);
sum[x]=sum[x<<1]+sum[x<<1|1];
}
LL query(int x,int l,int r,int L,int R){
if(R<L) return 0;
if(L<=l && r<=R) return sum[x];
int mid=(l+r)>>1;LL ret=0;if(lazy[x]) pushdown(x,mid-l+1,r-mid);
if(L<=mid) ret+=query(x<<1,l,mid,L,R);
if(mid<R) ret+=query(x<<1|1,mid+1,r,L,R);
return ret;
}
inline int findson(int x,int y){
while(top[x]!=top[y]){
if(Fa[top[x]]==y) return top[x];
x=Fa[top[x]];
}
return son[y];
}
inline void updSon(int x,int k){
if(x==rt) update(1,1,n,1,n,k);
else if(in[x]>=in[rt] || out[x]<out[rt]) update(1,1,n,in[x],out[x],k);
else {
int now=findson(rt,x);
update(1,1,n,1,in[now]-1,k);update(1,1,n,out[now]+1,n,k);
}
}
inline LL qSon(int x){
if(x==rt) return query(1,1,n,1,n);
else if(in[x]>=in[rt] || out[x]<out[rt]) return query(1,1,n,in[x],out[x]);
else {
int now=findson(rt,x);
return query(1,1,n,1,in[now]-1)+query(1,1,n,out[now]+1,n);
}
}
inline int qSiz(int x){
if(x==rt) return n;
else if(in[x]>=in[rt] || out[x]<out[rt]) return siz[x];
return n-siz[findson(rt,x)];
}
namespace lct{
int ch[MAXN][2];
inline bool isroot(int x){
return (ch[fa[x]][0]!=x && ch[fa[x]][1]!=x);
}
inline bool check(int x){
return (x==ch[fa[x]][1]);
}
inline void pushup(int x){
if(!ch[x][0]) ll[x]=x;
else ll[x]=ll[ch[x][0]];
if(!ch[x][1]) rr[x]=x;
else rr[x]=rr[ch[x][1]];
}
inline void pushdown(int x){
if(tag[x]){
tag[ch[x][0]]^=1;tag[ch[x][1]]^=1;
swap(ll[ch[x][0]],rr[ch[x][0]]);
swap(ll[ch[x][1]],rr[ch[x][1]]);tag[x]^=1;
swap(ch[x][0],ch[x][1]);
}
}
void pd(int x) {if(!isroot(x)) pd(fa[x]);pushdown(x);}
inline void rotate(int x){
int y=fa[x],z=fa[y];bool chk=check(x);
if(!isroot(y)) ch[z][check(y)]=x;
ch[y][chk]=ch[x][chk^1];fa[ch[x][chk^1]]=y;
ch[x][chk^1]=y;fa[y]=x;fa[x]=z;pushup(y);pushup(x);
}
inline void splay(int x){
pd(x);
for(;!isroot(x);rotate(x))
if(!isroot(fa[x])) rotate(check(x)==check(fa[x])?fa[x]:x);
}
inline void access(int x){
for(int y=0;x;y=x,x=fa[x]){
splay(x);if(y) updSon(ll[y],-1);
if(ch[x][1]) updSon(ll[ch[x][1]],1);
ch[x][1]=y;pushup(x);
}
}
inline void makeroot(int x){
access(x);splay(x);tag[x]^=1;
swap(ll[x],rr[x]);
}
}
signed main(){
// freopen("19.in","r",stdin);
// freopen("my.out","w",stdout);
n=rd(),m=rd();int x,y;char s[10];LL z;
for(int i=1;i<n;i++) {
x=rd(),y=rd();
add(x,y),add(y,x);
}
dfs1(1,0,1);dfs2(1,1);build(1,1,n);rt=1;
while(m--){
scanf("%s",s+1);x=rd();
if(s[3]=='L') lct::access(x);
if(s[3]=='C') lct::makeroot(x),rt=x;
if(s[3]=='Q') {
y=qSiz(x);z=qSon(x);
printf("%.10lf\n",(double)z/y);
}
}
return 0;
}
BZOJ 3779: 重组病毒(线段树+lct+树剖)的更多相关文章
- bzoj 3779 重组病毒 好题 LCT+dfn序+线段树分类讨论
题目大意 1.将x到当前根路径上的所有点染成一种新的颜色: 2.将x到当前根路径上的所有点染成一种新的颜色,并且把这个点设为新的根: 3.查询以x为根的子树中所有点权值的平均值. 分析 原题codec ...
- BZOJ 3779 重组病毒 LCT+线段树(维护DFS序)
原题干(由于是权限题我就直接砸出原题干了,要看题意概述的话在下面): Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力 ...
- bzoj 3779: 重组病毒 LCT+线段树+倍增
题目: 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒. 实验在一个封闭 ...
- 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 线段树
发现操作一很像一个LCT的access的操作. 然后答案就是路径上的虚边的数量. 然后考虑维护每一个点到根节点虚边的数量, 每次断开一条偏爱路径的时候,子树的值全部+1, 连接一条偏爱路径的时候,子树 ...
- bzoj 3779 重组病毒——LCT维护子树信息
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3779 调了很久……已经懒得写题解了.https://www.cnblogs.com/Zinn ...
- bzoj 3779: 重组病毒
一道好题~~ 一个点到根传染需要的时间是这段路径上不同颜色的数目,一个点子树到根平均传染时间就是加权平均数了(好像是废话). 所以只要用线段树维护dfs序就这个可以了,换根的话一个点的子树要么在dfs ...
- 【BZOJ】3779 重组病毒
[算法]Link-Cut Tree+线段树(维护DFS序) [题解]整整三天……T_T 这篇题解比较资瓷:permui 这道题虽然树形态没有变化,但用lct写的原因在于把题目中的操作一进行了神转化:每 ...
随机推荐
- 关于ps前端工程师简单配置
1.创建Web网页设计稿的预设参数 1920*1080 72 透明 2.定位组或定位图层 可以在ps选项栏中,勾选“自动选择”+组/图层 或者 ctrl键+组/图层: 3.视图 ...
- 使用cordova,监听安卓机物理返回按键,实现退出程序的功能
在使用html5开发app时,并不能像Android原生那样调取手机自身的方法.而cordova正好弥补了html5这一缺陷. 一,在cordova中文网http://cordova.axuer.co ...
- 前缀和+排序——cf1043E
先不考虑第二个条件 要求i和所有其他人的分数和最小,选择x还是y,可以推出一个公式,即差xi-yi小的j都选y,反之都选x 那么按照xi-yi排序即可 然后再考虑第二个条件,做减法就行 /* xi+y ...
- 高级运维(五):构建memcached服务、LNMP+memcached、使用Tomcat设置Session、Tomcat实现session共享
一.构建memcached服务 目标: 本案例要求先快速搭建好一台memcached服务器,并对memcached进行简单的添.删.改.查操作: 1> 安装memcached软件,并启动服务d ...
- bzoj1001 [ICPC-Beijing 2006]狼抓兔子
我满心以为本题正解为最短路,结果到处都是最大流…… 几乎所有的都写了什么“对偶图”跑最短路,但我真的不知道什么叫做对偶图---------------------------------------- ...
- Java桌球小游戏
版本一.出现窗口package cn.xjion.game;/** * 出现窗口 * @author xjion * */import java.awt.*;import javax.swing.*; ...
- 用java进行测试php写的接口
<?php /* * @Author: anchen * @Date: 2018-07-06 13:53:19 * @Last Modified by: anchen * @Last Modif ...
- babel/core 6.x升级到7.x要碰到的一些坑
刚学习react.js没多久,碰到各种坑.就比如这个问题,弄了我3个小时,终于解决了.其实就是一个小问题. 报错信息: Error: Cannot find module '@babel/core' ...
- 记录百度编辑器bug(在编辑框输入光标到达页面最底部时,功能区块会悬浮在页面最顶部并且与编辑框分离)
解决方案: //加入这段CSS#edui1_toolbarbox { position: relative !important; }
- 高效IO之Java IO体系(一)
更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 个人觉得可以用“字节流操作类和字符流操作类组成了Java IO体系”来高度概括J ...