bzoj 3779 重組病毒

2022-04-30 13:03:11 字數 3623 閱讀 4752

黑客們通過對已有的病毒反編譯,將許多不同的病毒重組,並重新編譯出了新型的重組病毒。這種病毒的繁殖和變異能力極強。為了阻止這種病毒傳播,某安全機構策劃了一次實驗,來研究這種病毒。

實驗在乙個封閉的區域網內進行。區域網內有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操作的存在,這個集合並不一定是始終不變的。

至此,安全機構認為已經不需要實際的實驗了,於是他們拜託你編寫乙個程式,模擬實驗的結果,並回答所有的詢問。

輸入的第一行包含兩個整數n和m,分別代表區域網中計算機的數量,以及操作和詢問的總數。

接下來n-1行,每行包含兩個整數x和y,表示區域網中編號為x和y的計算機之間有網線直接相連。

接下來m行,每行包含乙個操作或者詢問,格式如問題描述中所述。

對於每個詢問,輸出乙個實數,代表平均感染時間。輸出與答案的絕對誤差不超過 10^(-6)時才會被視為正確。

8 61 2

1 32 8

3 43 5

3 64 7

request 7

release 3

request 3

recenter 5

release 2

request 1

4.0000000000

2.0000000000

1.3333333333

n<=100000 ,m<=100000

調了幾個世紀終於調出來了……lct+dfs序線段樹。

令每個點權值為這個點到根的路徑上虛邊數+1,一開始時都是虛邊,點權即為深度。

操作1可以神轉換為access。在access

過程中,當前節點的右兒子所代表的子樹整體權值+1(因為虛邊+1),而即將拼接過來的子樹整體權值-1。

操作2因為有換根操作,所以需要分類討論一波(以下結論畫圖易得):

1. x=root

,查詢整棵樹;

2. root

不在x的子樹內,查詢原樹中x

的子樹;

3. root

在x的子樹內,查詢整棵樹去除掉包含root的以x的親兒子為根的子樹。

然後就可以開始瞎搞啦✔

update:原來的**有一點問題……重新寫了乙份。

1 #include2 #include3 #include4

#define ll long long

5#define lc(x) x<<1

6#define rc(x) x<<1|1

7using

namespace

std;

8const

int n=1e5+5;9

int n,m,x,y,cnt,dfn,rt=1

,first[n];

10int deep[n],in[n],out[n],fa[n][18

];11

char op[15

];12

intread()

1316

while(c>='

0'&&c<='9')

17return x*f;18}

19struct edgee[n<<1

];20

void ins(int u,int v);first[u]=cnt;}

21struct

sgt22

31void up(int x)

32void qadd(int x,ll w)

33void down(int

x)34

39void add(int x,int l,int

r,ll w)

4042 down(x);int mid=(l[x]+r[x])>>1;43

if(l<=mid)add(lc(x),l,r,w);

44if(r>mid)add(rc(x),l,r,w);

45up(x);46}

47 ll query(int x,int l,int

r)48

56}sgt;

57int find(int x,int

y)58

64void addson(int

x,ll w)

6573

else sgt.add(1,in[x],out

[x],w);74}

75struct

lct76

80void flip(int x)

81void down(int x)

82void rotate(int

x)83

87 fa[x]=z;fa[y]=x;fa[c[x][r]]=y;

88 c[y][l]=c[x][r];c[x][r]=y;89}

90void relax(int x)

91void splay(int

x)92

102rotate(x);

103}

104}

105int top(int x)

106void access(int

x)107

116}

117void makeroot(int x)

118}lct;

119void dfs(int

x)120

132out[x]=dfn;

133}

134double request(int

x)135

144return

1.0*sgt.query(1,in[x],out[x])/(out[x]-in[x]+1

);145

}146

intmain()

147160

}161

return0;

162 }

view code

BZOJ3779 重組病毒

題目大意 給一棵樹,每個點一開始顏色互不相同,支援三個操作 1.將乙個點到根的路徑染成一種新的顏色 2.將乙個新的點設為根,並將原來的根到這個點的路徑染成一種新的顏色 3.查詢乙個子樹 對於當前根 到根的路徑期望顏色數 真tm是道神題,idea實在是太妙了 首先由於第2個操作的特殊性,我們可以發現,...

BZOJ3779 重組病毒

窮哭了 難嗎?難碼.首先觀察一下操作一,就是乙個access,但是要改變子樹啊,lct不緇瓷,所以線段樹稍微維護一下。怎麼維護是乙個大難點啊。是要分類討論的。先找出實右子樹在原數上的根xxx。情況rt x rt x rt x 直接修改整顆樹。r trt rt在子樹中,令y r ty rt y rt ...

bzoj 3779 重組病毒

一道好題 乙個點到根傳染需要的時間是這段路徑上不同顏色的數目,乙個點子樹到根平均傳染時間就是加權平均數了 好像是廢話 所以只要用線段樹維護dfs序就這個可以了,換根的話乙個點的子樹要麼在dfs序中不變,要麼被截成了 1,l 和 r,n 兩段 當這個點為當前root的祖先 l和r即為包含當前根的這個點...