Description
再过三个多月就是圣诞节了,小R想送小Y一棵圣诞树作为节日礼物。因为他想让这棵圣诞树越大越好,所以当然是买不到能够让他满意的树的,因此他打算自己把这棵树拼出来。
现在,小R开始画这棵树的设计图纸了。因为这棵树实在太大,所以他采用了一种比较方便的方法。首先他定义了
m
+
1
m+1
m+1 棵树
T
0
T_0
T0 到
T
m
T_m
Tm。最开始他只画好了
T
0
T_0
T0 的图纸:就只有一个点,编号为0。
接着,对于每一棵树
T
i
T_i
Ti,他在第
T
a
i
T_{a_i}
Tai 棵树的第
c
i
c_i
ci 个点和第
T
b
i
T_{b_i}
Tbi 棵树的第
d
i
d_i
di 个点之间连上了一条长度为
l
i
li
li 的边。在
T
i
T_i
Ti 中,他保持
T
a
i
T_{a_i}
Tai 中的所有节点编号不变,然后如果
T
a
i
T_{a_i}
Tai 中有
s
s
s 个节点,他会把
T
b
i
T_{b_i}
Tbi 中的所有节点的编号加上
s
s
s。
终于,他画好了所有的树。现在他定义一颗大小为
n
n
n的树的美观度为
∑
i
=
0
n
−
1
∑
j
=
i
+
1
n
−
1
d
(
i
,
j
)
\sum_{i=0}^{n-1}\sum_{j=i+1}^{n-1}d(i,j)
∑i=0n−1∑j=i+1n−1d(i,j),其中
d
(
i
,
j
)
d(i,j)
d(i,j) 为这棵树中
i
i
i到
j
j
j的最短距离。
为了方便小R 选择等究竟拼哪一棵树,你可以分别告诉他
T
1
T_1
T1 到
T
m
T_m
Tm 的美观度吗?答案可能很大,请对
1
0
9
+
7
10^9 + 7
109+7 取模后输出。
Input
第一行输入一个正整数 T T T 表示数据组数。每组数据的第一行是一个整数 m m m,接下来 m m m 行每行五个整数 a i , b i , c i , d i , l i a_i, b_i, c_i, d_i, l_i ai,bi,ci,di,li,保证 0 < = a i , b i < i , 0 < = l i < = 1 0 9 , c i , d i 0 <= a_i, b_i < i, 0<= l_i<= 10^9,c_i, d_i 0<=ai,bi<i,0<=li<=109,ci,di 存在。
Output
对于每组询问输出m 行。第i 行输出Ti 的权值
Sample Input
1
2
0 0 0 0 2
1 1 0 0 4
Sample Output
2
28
Data Constraint
对于30% 的数据,
m
<
=
8
m <= 8
m<=8
对于60% 的数据,
m
<
=
16
m <= 16
m<=16
对于100% 的数据,
1
<
=
m
<
=
60
,
T
<
=
100
1 <= m<= 60,T<= 100
1<=m<=60,T<=100
分析:
假设树
C
C
C是由两棵树
A
A
A和
B
B
B合并而来,答案就是
a
n
s
[
A
]
+
a
n
s
[
B
]
+
s
u
m
[
A
]
∗
s
i
z
e
[
B
]
+
s
u
m
[
B
]
∗
s
i
z
e
[
A
]
+
s
i
z
e
[
A
]
∗
s
i
z
e
[
B
]
∗
L
ans[A]+ans[B]+sum[A]*size[B]+sum[B]*size[A]+size[A]*size[B]*L
ans[A]+ans[B]+sum[A]∗size[B]+sum[B]∗size[A]+size[A]∗size[B]∗L
其中
s
u
m
[
A
]
sum[A]
sum[A]表示所有点到A端连接的点的距离和,
s
u
m
[
B
]
sum[B]
sum[B]同理,
L
L
L为连接的边长。
s
i
z
e
size
size非常好维护,考虑求距离和。
由于距离和所在树也是由两棵树合并来的,考虑分治。
设
x
x
x为A端连接的点,考虑求
s
u
m
[
A
]
sum[A]
sum[A]。如果
x
x
x在
A
A
A树的左边的树,那么分治左边,然后加上右边树所有点到
x
x
x的距离。也就是右边树到右边连接点的距离和,加上右边连接点到
x
x
x的距离乘右边树的
s
i
z
e
size
size。
然后就是求树上两点的距离了,也可以考虑分治。如果两个点都在一边,直接递归这一边;否则为左边点到左边连接点,右边点到右边连接点,中间的边的和。
注意边界条件,然后开map记忆即可。
注意不能对
s
i
z
e
size
size取模,因为关系到节点的编号。
代码:
#include <iostream>
#include <cstdio>
#include <map>
#include <cmath>
const int maxn=67;
const long long mod=1e9+7;
typedef long long LL;
using namespace std;
int T,n,a,b,w;
LL x,y;
LL ans[maxn];
struct rec{
LL x,y;
};
bool operator <(rec a,rec b)
{
if (a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
struct node{
int l,r;
int len;
LL size,x,y;
map <LL,LL> sum;
map <rec,LL> dis;
}t[maxn];
LL getdis(int p,LL x,LL y)
{
if (x==y) return 0;
if (x>y) swap(x,y);
LL c=t[p].dis[(rec){x,y}];
if (c) return c;
LL sz=t[t[p].l].size;
if (y<=sz) c=getdis(t[p].l,x,y);
else
{
if (x>sz) c=getdis(t[p].r,x-sz,y-sz);
else c=getdis(t[p].l,x,t[p].x)+getdis(t[p].r,y-sz,t[p].y)+(LL)t[p].len;
}
c%=mod;
t[p].dis[(rec){x,y}]=c;
return c;
}
LL getsum(int p,LL x)
{
if (!p) return 0;
LL c=t[p].sum[x];
if (c) return c;
LL sz=t[t[p].l].size;
if (x<=sz) c=getsum(t[p].l,x)+((LL)t[p].len+getdis(t[p].l,x,t[p].x))%mod*(t[t[p].r].size%mod)%mod+getsum(t[p].r,t[p].y);
else c=getsum(t[p].r,x-sz)+((LL)t[p].len+getdis(t[p].r,x-sz,t[p].y))%mod*(t[t[p].l].size%mod)%mod+getsum(t[p].l,t[p].x);
c%=mod;
t[p].sum[x]=c;
return c;
}
int main()
{
scanf("%d",&T);
while (T--)
{
scanf("%d",&n);
t[0].size=1;
for (int i=1;i<=n;i++)
{
scanf("%d%d%lld%lld%d",&a,&b,&x,&y,&w);
x++,y++;
t[i].size=t[a].size+t[b].size;
t[i].l=a,t[i].r=b;
t[i].x=x,t[i].y=y;
t[i].len=w;
t[i].sum.clear();
t[i].dis.clear();
ans[i]=(ans[a]+ans[b]+t[b].size%mod*getsum(a,x)%mod+t[a].size%mod*getsum(b,y)%mod+(LL)w*(t[a].size%mod)%mod*(t[b].size%mod)%mod)%mod;
printf("%lld\n",ans[i]);
}
}
}