jzoj4211. 送你一颗圣诞树

版权声明:文章是蒟蒻写的,转载也别忘了注明出处。 https://blog.csdn.net/ganjingxian/article/details/86644203
  • 很明显,如果直接弄,点数非常多
  • 我们知道,一棵树的答案=两个子树的答案+size[a]*sum(b,d)+size[b]*sum(a,c)+size[a]*size[b]*l(其中sum(x,y)表示第x个树中,每个点到y的距离值和)
  • 那么问题就是怎么求sum,现在我们假设y在组成x这棵树的左子树里(右子树同理),那么对于左子树这部分的贡献,我们递归求,对于右子树,我们求得右子树每个点到c的距离和(因为右子树的点想要走到y,c是必经点),加上c到y的距离*size[b]+size[b]*l
  • 记dis(o,x,y)表示在第o棵树中x到y的距离,如果是分别在左子树或右子树,直接递归下去,否则转化为两个子问题+l
  • 注意,size是不能模的,但是它要参与运算,所以要先模size,不然会炸,然后用map来存之前求过的东西。
  • code map是co的
#include<cstdio>
#include<algorithm>
#include<map>
#include<cstring>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
using namespace std;
typedef long long ll;
const ll mo=1e+9+7;
struct node{
	ll a,b,c,d,l,s;
};
node t[65];
typedef pair<ll,ll> note;
map <note,ll>h[65];
ll ans[65],a,b,c,d,l;
int m;
ll dis(ll o,ll x,ll y){
	if (x>y) swap(x,y);
	if (!o||x==y) return 0;
	ll a=t[o].a,b=t[o].b,c=t[o].c,d=t[o].d,l=t[o].l;
	if (y<t[a].s) return dis(a,x,y)%mo;
	else if (x>=t[a].s) return dis(b,x-t[a].s,y-t[a].s)%mo;
	else{
		note k=make_pair(x,y);
		if (h[o].find(k)!=h[o].end()) return h[o][k]%mo;
		h[o][k]=((dis(a,x,c)%mo+t[o].l)%mo+dis(b,d,y-t[a].s))%mo;
		return h[o][k]%mo;
	}
}
ll sum(ll x,ll y){
	note k=make_pair(y,0);
	if (h[x].find(k)!=h[x].end()) return h[x][k];
	ll a=t[x].a,b=t[x].b,c=t[x].c,d=t[x].d,l=t[x].l; 
	if (y<t[a].s) {
		h[x][k]=(sum(a,y)+t[b].s%mo*(l+dis(a,y,c))%mo)%mo;
		h[x][k]=(h[x][k]+sum(b,d))%mo;
	}
	else {
		h[x][k]=(sum(b,y-t[a].s)+t[a].s%mo*(l+dis(b,y-t[a].s,d))%mo)%mo;
		h[x][k]=(h[x][k]+sum(a,c))%mo;
	}
	return h[x][k];
}
int main(){
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	int T;
	scanf("%d",&T);
	while (T--){
		memset(t,0,sizeof(t));
		t[0].s=1;
		memset(ans,0,sizeof(ans));
		scanf("%d",&m);
		fo(i,1,m){
			h[i].clear();
			scanf("%lld%lld%lld%lld%lld",&t[i].a,&t[i].b,&t[i].c,&t[i].d,&t[i].l);
			t[i].s=t[t[i].a].s+t[t[i].b].s;
		}
		fo(i,1,m){
			a=t[i].a; b=t[i].b; c=t[i].c; d=t[i].d; l=t[i].l; 
			ans[i]=(t[a].s%mo)*(t[b].s%mo)%mo*l%mo;
			ans[i]=((ans[i]+ans[a])%mo+ans[b])%mo;
			ans[i]=(ans[i]+t[b].s%mo*sum(a,c)%mo)%mo;
			ans[i]=(ans[i]+t[a].s%mo*sum(b,d)%mo)%mo;
			printf("%lld\n",ans[i]);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ganjingxian/article/details/86644203
今日推荐