Description
再过三个多月就是圣诞节了,小R想送小Y一棵圣诞树作为节日礼物。因为他想让这棵圣诞树越大越好,所以当然是买不到能够让他满意的树的,因此他打算自己把这棵树拼出来。
现在,小R开始画这棵树的设计图纸了。因为这棵树实在太大,所以他采用了一种比较方便的方法。首先他定义了m+1m+1m+1 棵树 T0T_0T0 到 TmT_mTm。最开始他只画好了 T0T_0T0 的图纸:就只有一个点,编号为0。
接着,对于每一棵树 TiT_iTi,他在第 TaiT_{a_i}Tai 棵树的第 cic_ici 个点和第 TbiT_{b_i}Tbi 棵树的第did_idi 个点之间连上了一条长度为 lilili 的边。在 TiT_iTi 中,他保持 TaiT_{a_i}Tai 中的所有节点编号不变,然后如果 TaiT_{a_i}Tai 中有 sss 个节点,他会把 TbiT_{b_i}Tbi 中的所有节点的编号加上sss。
终于,他画好了所有的树。现在他定义一颗大小为nnn的树的美观度为∑i=0n−1∑j=i+1n−1d(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) 为这棵树中iii到jjj的最短距离。
为了方便小R 选择等究竟拼哪一棵树,你可以分别告诉他 T1T_1T1 到 TmT_mTm 的美观度吗?答案可能很大,请对109+710^9 + 7109+7 取模后输出。
Input
第一行输入一个正整数 TTT 表示数据组数。每组数据的第一行是一个整数mmm,接下来 mmm 行每行五个整数ai,bi,ci,di,lia_i, b_i, c_i, d_i, l_iai,bi,ci,di,li,保证 0<=ai,bi<i,0<=li<=109,ci,di0 <= a_i, b_i < i, 0<= l_i<= 10^9,c_i, d_i0<=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<=8m <= 8m<=8
对于60% 的数据,m<=16m <= 16m<=16
对于100% 的数据,1<=m<=60,T<=1001 <= m<= 60,T<= 1001<=m<=60,T<=100
分析:
假设树CCC是由两棵树AAA和BBB合并而来,答案就是
ans[A]+ans[B]+sum[A]∗size[B]+sum[B]∗size[A]+size[A]∗size[B]∗Lans[A]+ans[B]+sum[A]*size[B]+sum[B]*size[A]+size[A]*size[B]*Lans[A]+ans[B]+sum[A]∗size[B]+sum[B]∗size[A]+size[A]∗size[B]∗L
其中sum[A]sum[A]sum[A]表示所有点到A端连接的点的距离和,sum[B]sum[B]sum[B]同理,LLL为连接的边长。
sizesizesize非常好维护,考虑求距离和。
由于距离和所在树也是由两棵树合并来的,考虑分治。
设xxx为A端连接的点,考虑求sum[A]sum[A]sum[A]。如果xxx在AAA树的左边的树,那么分治左边,然后加上右边树所有点到xxx的距离。也就是右边树到右边连接点的距离和,加上右边连接点到xxx的距离乘右边树的sizesizesize。
然后就是求树上两点的距离了,也可以考虑分治。如果两个点都在一边,直接递归这一边;否则为左边点到左边连接点,右边点到右边连接点,中间的边的和。
注意边界条件,然后开map记忆即可。
注意不能对sizesizesize取模,因为关系到节点的编号。
代码:
#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]);
}
}
}