1. 程式人生 > >BZOJ 3779: 重組病毒(線段樹+lct+樹剖)

BZOJ 3779: 重組病毒(線段樹+lct+樹剖)

n-1 for 病毒 網線 == [1] getchar() sca pushd

題面

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+樹剖)