zoukankan      html  css  js  c++  java
  • Bzoj3779 重组病毒

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 408  Solved: 163
    [Submit][Status][Discuss]

    Description

    黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒。这种病毒的繁殖和变异能力极强。为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒。
    实验在一个封闭的局域网内进行。局域网内有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+LCA+线段树 脑洞题

    初始的时候,每个结点的权值就是它的深度。

    观察发现每个结点的权值实际上就是它access的时候向上经过的虚边数量。

    于是1操作就是access,路上把LCT结点的原右儿子所在子树权值全部+1,把新右儿子所在子树权值全部-1,这一过程可以用DFS序+线段树维护

    2操作就是makeroot,自带一个access操作

    3操作换根比较麻烦,实际上只需要记录当前根,每次仍在最初的树上操作,根据原根与现根的位置关系讨论即可。

    ↑比如说这种情况,要修改的就是除了nowroot所在子树区间以外的左右两段(图中没有左段)区间

      

      1 /*by SilverN*/
      2 #include<algorithm>
      3 #include<iostream>
      4 #include<cstring>
      5 #include<cstdio>
      6 #include<cmath>
      7 #include<vector>
      8 #define LL long long
      9 using namespace std;
     10 const int mxn=100010;
     11 int read(){
     12     int x=0,f=1;char ch=getchar();
     13     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     14     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
     15     return x*f;
     16 }
     17 struct edge{
     18     int v,nxt;
     19 }e[mxn<<1];
     20 int hd[mxn],mct=0;
     21 void add_edge(int u,int v){
     22     e[++mct].v=v;e[mct].nxt=hd[u];hd[u]=mct;return;
     23 }
     24 namespace TC{
     25     struct node{
     26         int fa,top,son;
     27         int sz;
     28     }t[mxn];
     29     int dep[mxn],ind[mxn],out[mxn],dtime;
     30     int mp[mxn];
     31     void DFS(int u,int ff){
     32         dep[u]=dep[ff]+1;
     33         t[u].sz++;
     34         for(int i=hd[u],v;i;i=e[i].nxt){
     35             if(e[i].v==ff)continue;
     36             v=e[i].v;
     37             t[v].fa=u;
     38             DFS(v,u);
     39             t[u].sz+=t[v].sz;
     40             if(t[v].sz>t[t[u].son].sz)t[u].son=v;
     41         }
     42         return;
     43     }
     44     void DFS2(int u,int top){
     45         ind[u]=++dtime;
     46         mp[dtime]=u;
     47         t[u].top=top;
     48         if(t[u].son){
     49             DFS2(t[u].son,top);
     50             for(int i=hd[u];i;i=e[i].nxt){
     51                 if(e[i].v==t[u].son || e[i].v==t[u].fa)continue;
     52                 DFS2(e[i].v,e[i].v);
     53             }
     54         }
     55         out[u]=dtime;
     56         return;
     57     }
     58     int LCA(int x,int y){
     59         int last=0;
     60         while(t[x].top!=t[y].top){
     61             if(dep[t[x].top]<dep[t[y].top])swap(x,y);
     62             last=t[x].top;
     63             x=t[t[x].top].fa;
     64         }
     65         if(x==y)return last;
     66             else return t[y].son;
     67     }
     68 }
     69 int n,m,nowroot;
     70 struct SGT{
     71     #define lc rt<<1
     72     #define rc rt<<1|1
     73     struct node{
     74         LL smm,mk,mx;
     75     }t[mxn<<2];
     76     void pushup(int rt){
     77         t[rt].smm=t[lc].smm+t[rc].smm;
     78         return;
     79     }
     80     inline void PD(int l,int r,int rt){
     81         if(t[rt].mk){
     82             t[lc].mk+=t[rt].mk;
     83             t[rc].mk+=t[rt].mk;
     84             int mid=(l+r)>>1;
     85             t[lc].smm+=t[rt].mk*(LL)(mid-l+1);
     86             t[rc].smm+=t[rt].mk*(LL)(r-mid);
     87             t[lc].mx+=t[rt].mk;t[rc].mx+=t[rt].mk;
     88             t[rt].mk=0;
     89         }
     90         return;
     91     }
     92     void Build(int l,int r,int rt){
     93         if(l==r){
     94             t[rt].smm=t[rt].mx=TC::dep[TC::mp[l]];    return;
     95         }
     96         int mid=(l+r)>>1;
     97         Build(l,mid,lc);Build(mid+1,r,rc);
     98         pushup(rt);
     99         return;
    100     }
    101     void update(int L,int R,int v,int l,int r,int rt){
    102         if(L>R)return;
    103         if(L<=l && r<=R){
    104             t[rt].mk+=v;
    105             t[rt].smm+=(LL)v*(LL)(r-l+1);
    106             return;
    107         }
    108         PD(l,r,rt);
    109         int mid=(l+r)>>1;
    110         if(L<=mid)update(L,R,v,l,mid,lc);
    111         if(R>mid)update(L,R,v,mid+1,r,rc);
    112         pushup(rt);
    113         return;
    114     }
    115     LL qsum(int L,int R,int l,int r,int rt){
    116         if(L>R)return 0;
    117         if(L<=l && r<=R){return t[rt].smm;}
    118         PD(l,r,rt);
    119         LL res=0;
    120         int mid=(l+r)>>1;
    121         if(L<=mid)res+=qsum(L,R,l,mid,lc);
    122         if(R>mid)res+=qsum(L,R,mid+1,r,rc);
    123         pushup(rt);
    124         return res;
    125     }
    126     void Q_UPD(int x,int v){
    127         using namespace TC;
    128         int rt=nowroot;
    129         if(rt==x)update(1,n,v,1,n,1);
    130         else 
    131             if(ind[x]<ind[rt] && out[rt]<=out[x]){//两段区间 
    132                 rt=LCA(rt,x);
    133                 update(1,ind[rt]-1,v,1,n,1);
    134                 update(out[rt]+1,n,v,1,n,1);
    135             }
    136             else update(ind[x],out[x],v,1,n,1);
    137     }
    138     double Query(int x){
    139         using namespace TC;
    140         LL ans=0,sz=0;
    141         int rt=nowroot;
    142         if(rt==x)ans=qsum(1,n,1,n,1),sz=n;
    143         else if(ind[x]<ind[rt] && out[rt]<=out[x]){
    144                 rt=LCA(rt,x);
    145                 ans+=qsum(1,ind[rt]-1,1,n,1);
    146                 ans+=qsum(out[rt]+1,n,1,n,1);
    147                 sz=n-(out[rt]-ind[rt]+1);
    148             }
    149             else{
    150                 ans=qsum(ind[x],out[x],1,n,1),sz=out[x]-ind[x]+1;
    151             }
    152         double res=(double)ans/(double)sz;
    153         printf("%.10f
    ",res);
    154         return res;
    155     }
    156     #undef lc
    157     #undef rc
    158 }sgt;
    159 struct LCT{
    160     int ch[mxn][2],fa[mxn];
    161     bool rev[mxn];
    162     int st[mxn],top;
    163     inline bool isroot(int x){return (ch[fa[x]][0]!=x && ch[fa[x]][1]!=x);}
    164     void PD(int rt){
    165         if(rev[rt]){
    166             rev[ch[rt][0]]^=1;    rev[ch[rt][1]]^=1;
    167             swap(ch[rt][0],ch[rt][1]);
    168             rev[rt]^=1;
    169         }
    170         return;
    171     }
    172     void rotate(int x){
    173         int y=fa[x],z=fa[y],lc,rc;
    174         if(ch[y][0]==x)lc=0;else lc=1; rc=lc^1;
    175         if(!isroot(y)) ch[z][ch[z][1]==y]=x;
    176         fa[x]=z;fa[y]=x;
    177         fa[ch[x][rc]]=y;
    178         ch[y][lc]=ch[x][rc]; ch[x][rc]=y;
    179         return;
    180     }
    181     void Splay(int x){
    182         st[top=1]=x;
    183         for(int i=x;!isroot(i);i=fa[i])    st[++top]=fa[i];
    184         while(top)PD(st[top--]);
    185         while(!isroot(x)){
    186             int y=fa[x],z=fa[y];
    187             if(!isroot(y)){
    188                 if((ch[z][0]==y)^(ch[y][0]==x))rotate(x);
    189                 else rotate(y);
    190             }
    191             rotate(x);
    192         }
    193     }
    194     void access(int x){
    195         for(int y=0;x;x=fa[x]){
    196             Splay(x);
    197             if(ch[x][1]){
    198                 int now=ch[x][1];    PD(now);
    199                 while(ch[now][0]){now=ch[now][0];PD(now);}
    200                 sgt.Q_UPD(now,1);
    201             }
    202             if(y){
    203                 int now=y;    PD(now);
    204                 while(ch[now][0]){now=ch[now][0];PD(now);}
    205                 sgt.Q_UPD(now,-1);
    206             }
    207             ch[x][1]=y;
    208             y=x;
    209         }
    210         return;
    211     }
    212     void mkroot(int x){
    213         access(x);Splay(x);
    214         rev[x]^=1;
    215         nowroot=x;
    216         return;
    217     }
    218 }LT;
    219 void solve(){
    220     char opt[10];int x;
    221     while(m--){
    222         scanf("%s%d",opt,&x);
    223         if(opt[2]=='Q'){sgt.Query(x);continue;}//REQUEST
    224         else if(opt[2]=='C'){LT.mkroot(x);continue;}//RECENTER
    225         else if(opt[2]=='L'){LT.access(x);continue;}//RELEASE
    226 //        else Debug();
    227     }
    228     return;
    229 }
    230 int main(){
    231     int i,j;
    232     n=read();m=read();
    233     int u,v;
    234     for(i=1;i<n;i++){
    235         u=read();v=read();
    236         add_edge(u,v);add_edge(v,u);
    237     }
    238     TC::DFS(1,0);
    239     TC::DFS2(1,1);
    240     for(i=1;i<=n;i++) LT.fa[i]=TC::t[i].fa;    
    241     sgt.Build(1,n,1);
    242     nowroot=1;
    243     solve();
    244     return 0;
    245 }
    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 408  Solved: 163
    [Submit][Status][Discuss]

    Description

    黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒。这种病毒的繁殖和变异能力极强。为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒。
    实验在一个封闭的局域网内进行。局域网内有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

  • 相关阅读:
    FreeMarker缓存处理
    freemarker入门实例与源码研究准备工作
    Freemarker常用技巧(二)
    Freemarker常用技巧(一)
    Hessian与Spring整合
    Hessian学习
    数组常见的面试题
    关于排序的实现
    Redis与Memcache的区别
    JDBC编程步骤
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6728338.html
Copyright © 2011-2022 走看看