博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ3779重组病毒LCT
阅读量:6278 次
发布时间:2019-06-22

本文共 4434 字,大约阅读时间需要 14 分钟。

题目描述

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

实验在一个封闭的局域网内进行。局域网内有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操作的存在,这个集合并不一定是始终不变的。
至此,安全机构认为已经不需要实际的实验了,于是他们拜托你编写一个程序,模拟实验的结果,并回答所有的询问。

题解

我们可以来观察这两个操作。

1、将当前点到根染上一种新的颜色,这意味着这条路径上的点到其他点颜色是不一样的。

2、对x点进行操作1,然后把x作为根。

我们发现这两个操作和LCT中的access和makeroot一毛一样,重边代表两点颜色相同,轻边代表颜色不同。

然后就用LCT维护这个过程。

但要求区间查询,所以再加上线段树维护dfs序。

access时,如果断开一条重边,那么子树里答案要+1,如果连上一条重边,那么子树-1。

然后换根的话和遥远的国度那题一样,讨论一下当前点和根的关系就好了。

注意:线段树区间加别写错,子树加的时候要先findroot一下找到真正的子树根。

代码

#include
#include
#define N 100002using namespace std;typedef long long ll;char s[10];ll tr[N<<2],la[N<<2];int ch[N][2],fa[N],dfn[N],size[N],root,n,m,tot,top,head[N],deep[N];int p[N][20];bool rev[N];inline int rd(){ int x=0;char c=getchar();bool f=0; while(!isdigit(c)){
if(c=='-')f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x;}inline void pushd(int cnt,int l1,int l2){ tr[cnt<<1]+=la[cnt]*l1;la[cnt<<1]+=la[cnt]; tr[cnt<<1|1]+=la[cnt]*l2;la[cnt<<1|1]+=la[cnt]; la[cnt]=0;}void upd(int cnt,int l,int r,int L,int R,int x){ if(L>R)return; if(l>=L&&r<=R){tr[cnt]+=1ll*(r-l+1)*x;la[cnt]+=x;return;} int mid=(l+r)>>1; if(la[cnt])pushd(cnt,mid-l+1,r-mid); if(mid>=L)upd(cnt<<1,l,mid,L,R,x); if(mid
<<1|1,mid+1,r,L,R,x); tr[cnt]=tr[cnt<<1]+tr[cnt<<1|1];}ll query(int cnt,int l,int r,int L,int R){ if(L>R)return 0; if(l>=L&&r<=R)return tr[cnt]; int mid=(l+r)>>1;ll ans=0; if(la[cnt])pushd(cnt,mid-l+1,r-mid); if(mid>=L)ans+=query(cnt<<1,l,mid,L,R); if(mid
<<1|1,mid+1,r,L,R); return ans;}#define ls ch[x][0]#define rs ch[x][1]inline bool ge(int x){
return ch[fa[x]][1]==x;}inline bool isroot(int x){
return ch[fa[x]][1]!=x&&ch[fa[x]][0]!=x;} inline void rotate(int x){ int y=fa[x],o=ge(x); ch[y][o]=ch[x][o^1];fa[ch[y][o]]=y; if(!isroot(y))ch[fa[y]][ge(y)]=x;fa[x]=fa[y]; fa[y]=x;ch[x][o^1]=y; }inline void pushdown(int x){
if(rev[x]){rev[x]^=1;rev[ls]^=1;rev[rs]^=1;swap(ls,rs);}}inline void _pushdown(int x){
if(!isroot(x))_pushdown(fa[x]);pushdown(x);}inline void splay(int x){ _pushdown(x); while(!isroot(x)){ int y=fa[x]; if(isroot(y))rotate(x); else rotate(ge(x)==ge(y)?y:x),rotate(x); }}inline int jump(int x,int y){ if(y<=0)return x; for(int i=17;i>=0;--i)if((1<
=dfn[x]&&dfn[root]<=dfn[x]+size[x]-1){ int y=jump(root,deep[root]-deep[x]-1); upd(1,1,n,1,dfn[y]-1,tag);upd(1,1,n,dfn[y]+size[y],n,tag); } else upd(1,1,n,dfn[x],dfn[x]+size[x]-1,tag);}inline int findroot(int x){ pushdown(x); while(ch[x][0])x=ch[x][0],pushdown(x); return x;}inline void access(int x){ for(int y=0;x;y=x,x=fa[x]){ splay(x); if(ch[x][1])jia(findroot(ch[x][1]),1);if(y)jia(findroot(y),-1); ch[x][1]=y; }}inline void makeroot(int x){access(x);splay(x);rev[x]^=1;}struct edge{
int n,to;}e[N<<1];inline void add(int u,int v){e[++tot].n=head[u];e[tot].to=v;head[u]=tot;}void dfs(int u,int f){ dfn[u]=++top;size[u]=1;deep[u]=deep[f]+1; for(int i=1;(1<
<=deep[u];++i)p[u][i]=p[p[u][i-1]][i-1]; upd(1,1,n,dfn[u],dfn[u],deep[u]); for(int i=head[u];i;i=e[i].n)if(e[i].to!=f){ int v=e[i].to;fa[v]=u;p[v][0]=u; dfs(v,u);size[u]+=size[v]; }}int main(){ n=rd();m=rd();int x,y; for(int i=1;i
=dfn[x]&&dfn[root]<=dfn[x]+size[x]-1){ int y=jump(root,deep[root]-deep[x]-1); sum=(double)(query(1,1,n,1,dfn[y]-1)+query(1,1,n,dfn[y]+size[y],n))/(n-size[y]); } else sum=(double)query(1,1,n,dfn[x],dfn[x]+size[x]-1)/size[x]; printf("%.10lf\n",sum); } } return 0;}

转载于:https://www.cnblogs.com/ZH-comld/p/10244707.html

你可能感兴趣的文章
python中一切皆对象------类的基础(五)
查看>>
modprobe
查看>>
android中用ExpandableListView实现三级扩展列表
查看>>
%Error opening tftp://255.255.255.255/cisconet.cfg
查看>>
java读取excel、txt 文件内容,传到、显示到另一个页面的文本框里面。
查看>>
《从零开始学Swift》学习笔记(Day 51)——扩展构造函数
查看>>
python多线程队列安全
查看>>
[汇编语言学习笔记][第四章第一个程序的编写]
查看>>
android 打开各种文件(setDataAndType)转:
查看>>
补交:最最原始的第一次作业(当时没有选上课,所以不知道)
查看>>
Vue实例初始化的选项配置对象详解
查看>>
PLM产品技术的发展趋势 来源:e-works 作者:清软英泰 党伟升 罗先海 耿坤瑛
查看>>
vue part3.3 小案例ajax (axios) 及页面异步显示
查看>>
浅谈MVC3自定义分页
查看>>
.net中ashx文件有什么用?功能有那些,一般用在什么情况下?
查看>>
select、poll、epoll之间的区别总结[整理]【转】
查看>>
CSS基础知识(上)
查看>>
PHP中常见的面试题2(附答案)
查看>>
26.Azure备份服务器(下)
查看>>
mybatis学习
查看>>