黑客們通過對已有的病毒反編譯,將許多不同的病毒重組,並重新編譯出了新型的重組病毒。這種病毒的繁殖和變異能力極強。為了阻止這種病毒傳播,某安全機構策劃了一次實驗,來研究這種病毒。
實驗在乙個封閉的區域網內進行。區域網內有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 #include4view code#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 }
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即為包含當前根的這個點...