3779: 重组病毒
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 315 Solved: 124
[ 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操作的存在,这个集合并不一定是始终不变的。
至此,安全机构认为已经不需要实际的实验了,于是他们拜托你编写一个程序,模拟实验的结果,并回答所有的询问。
实验在一个封闭的局域网内进行。局域网内有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行,每行包含一个操作或者询问,格式如问题描述中所述。
接下来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
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
2.0000000000
1.3333333333
HINT
N < = 1 00 000 M < = 1 00 000
Source
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
const int maxn = 1E5 + 10;
const int T = 4;
const int N = 17;
typedef double DB;
typedef long long LL;
int n,m,dfs_clock,rt = 1,tp,ch[maxn][2],fa[maxn],pfa[maxn],rev[maxn]
,stk[maxn],L[maxn],Name[maxn],dfn[maxn],out[maxn],tfa[maxn][N],Add[maxn*T];
LL sum[maxn*T]; char s[20];
vector <int> v[maxn];
int LCA(int p,int q)
{
if (L[p] < L[q]) swap(p,q);
for (int i = N - 1; i >= 0; i--)
if (L[p] - (1 << i) >= L[q])
p = tfa[p][i];
if (p == q) return p;
for (int i = N - 1; i >= 0; i--)
if (tfa[p][i] != tfa[q][i])
p = tfa[p][i],q = tfa[q][i];
return tfa[p][0];
}
int Quickfa(int x,int y)
{
for (int now = 0; y; y >>= 1,now++)
if (y & 1) x = tfa[x][now];
return x;
}
void Push(int o,int l,int r)
{
if (!Add[o]) return;
sum[o] += 1LL * (r - l + 1) * Add[o];
if (l == r) {Add[o] = 0; return;}
Add[o<<1] += Add[o]; Add[o<<1|1] += Add[o]; Add[o] = 0;
}
void Build(int o,int l,int r)
{
if (l == r) {sum[o] = L[Name[l]]; return;}
int mid = l + r >> 1;
Build(o<<1,l,mid); Build(o<<1|1,mid+1,r);
sum[o] = sum[o<<1] + sum[o<<1|1];
}
void Modify(int o,int l,int r,int ql,int qr,int k)
{
if (ql <= l && r <= qr) {Add[o] += k; Push(o,l,r); return;}
int mid = l + r >> 1; Push(o,l,r);
if (ql <= mid) Modify(o<<1,l,mid,ql,qr,k); else Push(o<<1,l,mid);
if (qr > mid) Modify(o<<1|1,mid+1,r,ql,qr,k); else Push(o<<1|1,mid+1,r);
sum[o] = sum[o<<1] + sum[o<<1|1];
}
LL Query(int o,int l,int r,int ql,int qr)
{
Push(o,l,r);
if (ql <= l && r <= qr) return sum[o];
int mid = l + r >> 1; LL ret = 0;
if (ql <= mid) ret = Query(o<<1,l,mid,ql,qr);
if (qr > mid) ret += Query(o<<1|1,mid+1,r,ql,qr);
return ret;
}
void pushdown(int x)
{
if (!rev[x]) return;
swap(ch[x][0],ch[x][1]);
for (int i = 0; i < 2; i++)
if (ch[x][i]) rev[ch[x][i]] ^= 1;
rev[x] = 0;
}
void rotate(int x)
{
int y = fa[x],z = fa[y];
pfa[x] = pfa[y]; pfa[y] = 0;
int d = ch[y][0] == x ? 0 : 1;
ch[y][d] = ch[x][d^1]; fa[ch[y][d]] = y;
ch[x][d^1] = y; fa[y] = x; fa[x] = z;
if (z) ch[z][ch[z][1] == y] = x;
}
void splay(int x)
{
for (int z = x; z; z = fa[z]) stk[++tp] = z;
while (tp) pushdown(stk[tp--]);
for (int y = fa[x]; y; rotate(x),y = fa[x])
if (fa[y]) rotate((ch[y][0] == x) ^ (ch[fa[y]][0] == y) ? x : y);
}
void Change(int x,int y,int k)
{
int lca = LCA(x,y);
if (x == y) puts("Wrong!");
if (lca == x)
{
y = Quickfa(y,L[y] - L[x] - 1);
if (dfn[y] > 1) Modify(1,1,n,1,dfn[y] - 1,k);
if (out[y] < n) Modify(1,1,n,out[y] + 1,n,k);
}
else Modify(1,1,n,dfn[x],out[x],k);
}
int FindRoot(int x)
{
for ( ; ; x = ch[x][0])
{
pushdown(x);
if (!ch[x][0]) break;
}
return x;
}
void Access(int x)
{
for (int u = 0; x; u = x,x = pfa[x])
{
splay(x);
if (ch[x][1])
{
fa[ch[x][1]] = 0; pfa[ch[x][1]] = x;
Change(FindRoot(ch[x][1]),rt,1);
}
ch[x][1] = u;
if (u)
{
fa[u] = x; pfa[u] = 0;
Change(FindRoot(u),rt,-1);
}
}
}
void ChangeRoot(int x) {Access(x); splay(x); rev[x] ^= 1;}
void Dfs(int x,int from)
{
dfn[x] = ++dfs_clock; Name[dfs_clock] = x;
for (int i = 1; i < N; i++) tfa[x][i] = tfa[tfa[x][i-1]][i-1];
for (int i = 0; i < v[x].size(); i++)
{
int to = v[x][i];
if (to == from) continue; pfa[to] = x;
L[to] = L[x] + 1; tfa[to][0] = x; Dfs(to,x);
}
out[x] = dfs_clock;
}
int getint()
{
char ch = getchar(); int ret = 0;
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret * 10 + ch - '0',ch = getchar();
return ret;
}
int getcom()
{
scanf("%s",s);
if (s[2] == 'L') return 1;
if (s[2] == 'C') return 2;
return 3;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
n = getint(); m = getint();
for (int i = 1; i < n; i++)
{
int x = getint(),y = getint();
v[x].push_back(y); v[y].push_back(x);
}
L[1] = 1; Dfs(1,0); Build(1,1,n);
while (m--)
{
int com = getcom(),now = getint();
if (com == 1) Access(now),splay(now);
else if (com == 2) ChangeRoot(now),rt = now;
else
{
if (now == rt) printf("%.10lf\n",(DB)(Query(1,1,n,1,n)) / (DB)(n));
else
{
int lca = LCA(rt,now);
if (lca == now)
{
int y = Quickfa(rt,L[rt] - L[now] - 1),tot;
LL Sum = 0; tot = dfn[y] - 1 + n - out[y];
if (dfn[y] > 1) Sum = Query(1,1,n,1,dfn[y] - 1);
if (out[y] < n) Sum += Query(1,1,n,out[y] + 1,n);
printf("%.10lf\n",(DB)(Sum) / (DB)(tot));
}
else
{
int tot = out[now] - dfn[now] + 1;
LL Sum = Query(1,1,n,dfn[now],out[now]);
printf("%.10lf\n",(DB)(Sum) / (DB)(tot));
}
}
}
}
return 0;
}