未知:zi——题解

3 篇文章 0 订阅
1 篇文章 0 订阅

//这题的名字真清奇。
【问题描述】
我们有 m+1棵树 ,分别是 T0,T1,…,Tm。其中 T0是一棵只有个点的树,点的编号为 0。
生成第 i棵树我们需要五个参数 ai,bi,ci,di,li(ai,bi < i)。我们生成第 。我们生成第i棵树是 将第ai棵树的ci号点和第bi棵树的di号点用一条长度为li的边连接起来形成新的树(不会改变原来两棵树不会改变原来两棵树不会改变原来两棵树不会改变原来两棵树)。下面我们需要对新树中的点重编号:对于原来在 第ai棵树中的点,我们不会改变他的编号;对于原来在第 bi棵树中的点,我们 会将他们的编号加上第ai棵树的点个数作为新编号 。
定义
F(Ti)=该树的任意两点的距离和。
现在希望你求出 ∀1≤i≤m,F(Ti)是多少 。
【输入格式】
第一行 一个整数 m。
接下来每行五个整数 ai,bi,ci,di,li代表第i棵树的生成方式 。
【输出格式】
m行,每行一个整数 ,代表F(Ti)mod(10^9+7)的值 。
【样例输入】
3
0 0 0 0 2
1 1 0 0 4
2 2 1 0 3
【样例输出】
2
28
216
【数据规模与约定】
对于 30%的数据, 1≤m≤10。
对于 60%的数据 ,每棵 树的点数 个数 不超过 10^5。
对于 100%的数据 ,1≤m≤60。
——————————————
直接上代码。
所有思路全写在代码里了。
(十分惭愧的借鉴了标程并且自己根据标程的理解写了注释)
(这题自我感觉很难TAT,至少不是我这种蒟蒻能想到的……)

#include<map>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int p=1e9+7;
inline int read(){
    int X=0,w=1; char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
    return X*w;
}
struct{
    ll size;//树大小 
    ll lsum;//f[i]
}t[61];//第i棵树 
map< pair<ll,ll>, ll > mp;
ll a[61],b[61],c[61],d[61],l[61];
ll dis(ll k,ll u,ll v){//k树所u~v的距离
    if(k==0)return 0;
    //想法:
    //对于原树来说,它的构成也是由两棵树组成的
    //u,v同在一棵树a上,那么就缩小树为a不断递归下去 
    //在b同理
    //如果不在同一棵树上,如u在b树,v在a树
    //那么返回为u~d+a~c+l
    //反之亦然 
    if(u>=t[a[k]].size&&v>=t[a[k]].size){
        return dis(b[k],u-t[a[k]].size,v-t[a[k]].size);
    }else if(u<t[a[k]].size&&v<t[a[k]].size){
        return dis(a[k],u,v);
    }else{
        if(u>=t[a[k]].size){
            return dis(b[k],u-t[a[k]].size,d[k])+dis(a[k],v,c[k])+l[k];
        }else{
            return dis(b[k],v-t[a[k]].size,d[k])+dis(a[k],u,c[k])+l[k];
        }
    }
}
ll dfs(ll k,ll u){//k树所有点到u的距离和 
    if(k==0)return 0;
    if(mp[make_pair(k,u)])return mp[make_pair(k,u)];
    //想法:
    //对于原树来说,它的构成也是由两棵树组成的
    //如果u在b树上,那么就相当于b树到u的距离+a树到c的距离+a树点数*(l+d~u的距离)
    //u在a树上同理 
    if(u>=t[a[k]].size){
        return mp[make_pair(k,u)]=
            dfs(b[k],u-t[a[k]].size)+
            dfs(a[k],c[k])+
            t[a[k]].size*(l[k]+dis(b[k],u-t[a[k]].size,d[k]));
    }else{
        return mp[make_pair(k,u)]=
            dfs(a[k],u)
            +dfs(b[k],d[k])
            +t[b[k]].size*(l[k]+dis(a[k],u,c[k]));
    }
}
int main(){
    freopen("zi.in","r",stdin);
    freopen("zi.out","w",stdout);
    int m=read();
    t[0].size=1;
    t[0].lsum=0;
    for(int i=1;i<=m;i++){
        a[i]=read();
        b[i]=read();
        c[i]=read();
        d[i]=read();
        l[i]=read();
        t[i].size=t[a[i]].size%p+t[b[i]].size%p;//显然 
        t[i].size%=p;
        t[i].lsum+=t[a[i]].lsum+t[b[i]].lsum;//显然 
        t[i].lsum%=p;
        ll k=t[a[i]].size%p*t[b[i]].size%p*l[i]%p;//显然 
        t[i].lsum+=k;
        t[i].lsum%=p;
        t[i].lsum+=dfs(a[i],c[i])%p*t[b[i]].size%p+dfs(b[i],d[i])%p*t[a[i]].size%p;//不那么显然
        //我们a树的点要到达b树的点,减去所有l后就相当于b到d的距离和*a树点的个数+a到c的距离和*b树点的个数
        t[i].lsum%=p;
    }
    for(int i=1;i<=m;i++){
        printf("%lld\n",t[i].lsum);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值