您的位置:首页 > 其它

jzoj 3583. 【GDOI2014模拟】小A的树

2017-12-25 21:09 218 查看
Description

小A有一棵N个点的树,每个点都有一个小于2^20的非负整数权值。现在小A从树中随机选择一个点x,再随机选择一个点y(x、y可以是同一个点),并对从x到y的路径上所有的点的权值分别做and、or、xor运算,最终会求得三个整数。小A想知道,他求出的三个数的期望值分别是多少。

Input

输入文件包含多组测试数据。

第一行,一个整数T,表示测试数据的组数。

接下来的T节,每节表示一组测试数据,格式如下:

第一行,一个整数N。

第二行,N个整数,其中第i个整数表示第i个点的权值。

接下来的N-1行,每行两个整数a、b,表示树中有一条连接a、b的边。

Output

T行,每行三个实数,结果保留3位小数,其中第i行的三个实数表示由第i组测试数据求得的三个期望值(按照and、or、xor的顺序)。

Sample Input

1

4

1 2 3 4

1 2

2 3

2 4

Sample Output

0.875 4.250 3.375

Data Constraint

对于20%的数据,1<=N<=1000;

对于另外20%的数据,N个点构成一条链;

对于全部的数据,1<=N<=100000,1<=T<=5。

分析:

对于每一种运算,可以把每一位独立出来,给每一位生成一棵树,每个点的权值就是0或1,如果x到y的路径的运算结果为1,则该路径在该位有贡献。那么这棵树的贡献就是,part_sum*(2^k)/(n*n),k就是第k位。我们可以用树形dp求。设f[x,0/1],g[x,0/1],h[x,0/1]表示and,or,xor运算,从x子树内任意一点到x的路径最后结果为0/1的路径数,显然经过x的路径数就是两个不同儿子的状态相乘(这个状态自己推,是真的烦)。

注意爆栈。

代码:

const
maxn=200001;
maxv=20;

type
node=record
y,next:longint;
end;

var
f,g,h:array [1..maxn,0..1] of int64;
a:array [1..maxn,1..40] of integer;
ls:array [1..maxn] of longint;
sf,sg,sh:array [1..maxn,0..1] of int64;
adge:array [1..maxn*2] of node;
v:array [1..maxn] of longint;
t,n,i,m:longint;
ef,eg,eh,c:extended;
sumf,sumg,sumh:extended;
procedure add(x,y:longint);
begin
inc(m);
adge[m].y:=y;
adge[m].next:=ls[x];
ls[x]:=m;
end;

procedure dfs(x:longint;dep:longint);
var t,i:longint;
begin
f[x,0]:=0; f[x,1]:=0;
g[x,0]:=0; g[x,1]:=0;
h[x,0]:=0; h[x,1]:=0;
sf[x,0]:=0; sh[x,0]:=0; sg[x,0]:=0;
sf[x,1]:=0; sh[x,1]:=0; sg[x,1]:=0;
f[x,a[x,dep]]:=1; g[x,a[x,dep]]:=1; h[x,a[x,dep]]:=1;
t:=ls[x];
while t>0 do
begin
with adge[t] do
begin
if v[y]=dep-1 then
begin
v[y]:=v[y]+1;
dfs(y,dep);
if a[x,dep]=0 then
begin
f[x,0]:=f[x,0]+f[y,0];
f[x,1]:=f[x,1]+f[y,1];
g[x,0]:=g[x,0]+g[y,1]+g[y,0];
h[x,0]:=h[x,0]+h[y,0];
h[x,1]:=h[x,1]+h[y,1];
ef:=ef+sf[x,0]*f[y,1]+sf[x,1]*f[y,0];
eh:=eh+sh[x,1]*h[y,0]+sh[x,0]*h[y,1]+sh[x,1]*h[y,1];
end
else
begin
f[x,0]:=f[x,0]+f[y,1];
f[x,1]:=f[x,1]+f[y,0];
g[x,0]:=g[x,0]+g[y,0];
g[x,1]:=g[x,1]+g[y,1];
h[x,1]:=h[x,1]+h[y,0]+h[y,1];
ef:=ef+sf[x,0]*f[y,0]+sf[x,1]*f[y,1];
eg:=eg+sg[x,1]*g[y,1];
eh:=eh+(sh[x,0]+sh[x,1])*(h[y,0]+h[y,1]);
end;
sf[x,0]:=sf[x,0]+f[y,0];
sf[x,1]:=sf[x,1]+f[y,1];
sg[x,0]:=sg[x,0]+g[y,0];
sg[x,1]:=sg[x,1]+g[y,1];
sh[x,0]:=sh[x,0]+h[y,0];
sh[x,1]:=sh[x,1]+h[y,1];
end;
t:=next;
end;
end;
if a[x,dep]=0 then
begin
ef:=ef+sf[x,1];
eh:=eh+sh[x,1];
end
else
begin
ef:=ef+sf[x,0]+0.5;
eg:=eg+sg[x,1]+0.5;
eh:=eh+sh[x,0]+sh[x,1]+0.5;
end;
end;

procedure main;
var i,x,k,y,j:longint;
pow:extended;
begin
readln(n);
m:=0;
for i:=1 to n do
begin
read(x); k:=0;
while x>0 do
begin
inc(k);
a[i,k]:=x and 1;
x:=x shr 1;
end;
for j:=k+1 to 20 do
a[i,j]:=0;
ls[i]:=0; v[i]:=0;
end;
for i:=1 to n-1 do
begin
readln(x,y);
add(x,y);
add(y,x);
end;
sumf:=0; sumg:=0; sumh:=0; pow:=1;
for i:=1 to 20 do
begin
ef:=0; eh:=0; eg:=0;
v[1]:=i;
dfs(1,i);
sumf:=sumf+pow*ef/n/n*2;
sumh:=sumh+pow*eh/n/n*2;
sumg:=sumg+pow*eg/n/n*2;
pow:=pow*2;
end;
writeln(sumg:0:3,' ',sumh:0:3,' ',sumf:0:3);
end;

begin
readln(t);
for i:=1 to t do
main;
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: