zoukankan      html  css  js  c++  java
  • JZOJ 4211. 【五校联考1day2】送你一颗圣诞树(分治)

    JZOJ 4211. 【五校联考1day2】送你一颗圣诞树

    题目

    Description

    再过三个多月就是圣诞节了,小R想送小Y一棵圣诞树作为节日礼物。因为他想让这棵圣诞树越大越好,所以当然是买不到能够让他满意的树的,因此他打算自己把这棵树拼出来。

    现在,小R开始画这棵树的设计图纸了。因为这棵树实在太大,所以他采用了一种比较方便的方法。首先他定义了 m + 1 m+ 1 m+1棵树 T 0 T0 T0 T m Tm Tm。最开始他只画好了 T 0 T0 T0 的图纸:就只有一个点,编号为0。

    接着,对于每一棵树 T i Ti Ti,他在 T a i Tai Tai的第 c i ci ci个点和 T b i Tbi Tbi的第 d i di di个点之间连上了一条长度为 l i li li的边。在 T i Ti Ti中,他保持 T a i Tai Tai中的所有节点编号不变,然后如果 T a i Tai Tai中有 s s s个节点,他会把 T b i Tbi Tbi中的所有节点的编号加上 s s s

    终于,他画好了所有的树。现在他定义一颗大小为n 的树的美观度为在这里插入图片描述其中 d ( i , j ) d(i,j) d(i,j) 为这棵树中i 到j 的最短距离。

    为了方便小R选择等究竟拼哪一棵树,你可以分别告诉他 T 1 T1 T1 T m Tm 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 ai, bi, ci, di, li ai,bi,ci,di,li,保证 0 ≤ a i , b i < i 0≤ai, bi < i 0ai,bi<i 0 ≤ l i ≤ 1 0 9 0≤li≤10^9 0li109 c i , d i ci, di ci,di存在。

    Output

    对于每组询问输出 m m m行。第 i i i行输出 T i Ti 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 m8
    对于60% 的数据, m ≤ 16 m≤16 m16
    对于100% 的数据, 1 ≤ m ≤ 60 1≤m≤60 1m60 T ≤ 100 T≤100 T100

    题解

    • 点数到最后可能会有 2 60 2^{60} 260个,会很大,不可能每个都存下来。

    • 只考虑怎么计算要求的答案就好。

    • 对于每一棵(题目写的是“颗”)树 i i i,记录 e [ i ] . a , e [ i ] . b , e [ i ] . c , e [ i ] . d , e [ i ] . l e[i].a,e[i].b,e[i].c,e[i].d,e[i].l e[i].ae[i].be[i].ce[i].de[i].l如题目中的 a , b , c , d , l a,b,c,d,l abcdl,记录 e [ i ] . s e[i].s e[i].s表示树的大小。为了方便计算,把节点编号统一 + 1 +1 +1

    • 易得 e [ i ] . s = e [ e [ i ] . a ] . s + e [ e [ i ] . b ] . s e[i].s=e[e[i].a].s+e[e[i].b].s e[i].s=e[e[i].a].s+e[e[i].b].s.

    • 定义函数 a l l ( T , x ) all(T,x) all(T,x)表示 T T T树上所有节点到 x x x节点的距离和(其中 x x x是在 T T T树中的编号)。

    • 定义函数 t o ( T , x , y ) to(T,x,y) to(T,x,y)表示 T T T树上节点 x x x到节点 y y y的距离(其中 x , y x,y x,y都是 T T T树中的编号)。

    • 发现只有这两个函数,就可以计算出答案,而且这两个函数可以通过自己不断类似分治地求答案。

    • 部分式子如下:

    • 先令 a = e [ i ] . a , b = e [ i ] . b , c = e [ i ] . c , d = e [ i ] . d a=e[i].a,b=e[i].b,c=e[i].c,d=e[i].d a=e[i].ab=e[i].bc=e[i].cd=e[i].d

    • 那么 a n s [ i ] = a n s [ a ] ∗ a n s [ b ] + e [ a ] . s ∗ e [ b ] . s ∗ e [ i ] . l + e [ a ] . s ∗ a l l ( b , d ) + e [ b ] . s ∗ a l l ( a , c ) ans[i]=ans[a]*ans[b]+e[a].s*e[b].s*e[i].l+e[a].s*all(b,d)+e[b].s*all(a,c) ans[i]=ans[a]ans[b]+e[a].se[b].se[i].l+e[a].sall(b,d)+e[b].sall(a,c).

    • a l l ( T , x ) all(T,x) all(T,x)

    • 1、如果 e [ T ] . s = 1 e[T].s=1 e[T].s=1,返回值为 0 0 0

    • 2、如果 x x x在左子树上,返回值为 a l l ( a , x ) + a l l ( b , d ) + e [ b ] . s ∗ ( e [ T ] . l + t o ( a , x , c ) ) all(a,x)+all(b,d)+e[b].s*(e[T].l+to(a,x,c)) all(a,x)+all(b,d)+e[b].s(e[T].l+to(a,x,c))

    • 3、如果 x x x在右子树上,返回值为 a l l ( b , x − e [ a ] . s ) + a l l ( a , c ) + e [ a ] . s ∗ ( e [ T ] . l + t o ( b , x − e [ a ] . s , d ) ) all(b,x-e[a].s)+all(a,c)+e[a].s*(e[T].l+to(b,x-e[a].s,d)) all(b,xe[a].s)+all(a,c)+e[a].s(e[T].l+to(b,xe[a].s,d))。( x − e [ a ] . s x-e[a].s xe[a].s是转化为右子树中的编号)

    • t o ( T , x , y ) to(T,x,y) to(T,x,y):保证 x ≤ y x≤y xy

    • 1、如果 x = y x=y x=y,返回值为 0 0 0

    • 2、如果 x , y x,y x,y都在左子树上,返回值为 t o ( a , x , y ) to(a,x,y) to(a,x,y)

    • 3、如果 x , y x,y x,y都在右子树上,返回值为 t o ( b , x , y ) to(b,x,y) to(b,x,y)

    • 4、如果 x x x在左子树上, y y y在右子树上,返回值为 t o ( a , x , c ) + e [ T ] . l + t o ( b , y − e [ a ] . s , d ) to(a,x,c)+e[T].l+to(b,y-e[a].s,d) to(a,x,c)+e[T].l+to(b,ye[a].s,d)。( y − e [ a ] . s y-e[a].s ye[a].s是转化为右子树中的编号)

    • 这样就能解决 60 60 60分了。

    • 因为有很多重复计算的,所以考虑记忆化,

    • 但是函数带的参数过大,需要用哈希表来存储。

    • 对于 a l l all all函数,存入 t ∗ x t*x tx

    • 对于 t o to to函数,存入 t ∗ x ∗ y t*x*y txy

    • 模数取 2 ∗ 1 0 5 + 9 2*10^5+9 2105+9,哈希表大小 5 ∗ 1 0 5 5*10^5 5105即可。

    • 记得每次计算都要模数,否则会出现负数,而且错误总是难以查出。

    代码

    #include<cstdio>
    #include<cstring>
    using namespace std;
    #define LL long long 
    #define md 1000000007
    #define z 200009
    LL m,tn;
    struct node
    {
    	LL s,l,a,b,c,d;
    }e[61];
    LL ans[61];
    struct
    {
    	LL u,v,s,t,id;
    }hx[500010],hs[500010];
    LL hash(LL t,LL v)
    {
    	LL x=(t%z)*(v%z)%z;
    	while(hs[x].id==tn+1)
    	{
    		if(hs[x].t==t&&hs[x].v==v) return x;
    		x++;		
    		if(x>500000) x=1;
    	}
    	return -x;
    }
    LL haxi(LL t,LL u,LL v)
    {
    	LL x=(t%z)*(u%z)%z*(v%z)%z;
    	while(hx[x].id==tn+1)	
    	{
    		if(hx[x].t==t&&hx[x].u==u&&hx[x].v==v) return x;
    		x++;
    		if(x>500000) x=1;
    	}
    	return -x;
    }
    LL to(LL t,LL u,LL v)
    {
    	LL ss=e[e[t].a].s,sum;
    	LL hs1=haxi(t,u,v);
    	if(hs1>0) return hx[hs1].s; 
    	if(u>v) 
    	{
    		LL tp=u;u=v,v=tp;
    	}
    	if(u==v) return 0;
    	if(v<=ss) sum=to(e[t].a,u,v);
    	else if(u>ss) sum=to(e[t].b,u-ss,v-ss);
    	else sum=(to(e[t].a,u,e[t].c)+to(e[t].b,v-ss,e[t].d)+e[t].l)%md;
    	hx[-hs1].t=t;
    	hx[-hs1].s=sum%md;
    	hx[-hs1].u=u;
    	hx[-hs1].v=v;
    	hx[-hs1].id=tn+1;
    	return sum;
    }
    LL all(LL t,LL v)
    {
    	LL ss=e[e[t].a].s,sum;
    	LL hs1=hash(t,v);
    	if(hs1>0) return hs[hs1].s;
    	if(e[t].s==1) return 0;
    	if(v<=ss) sum=(all(e[t].a,v)+all(e[t].b,e[t].d)+e[e[t].b].s%md*e[t].l%md+e[e[t].b].s%md*to(e[t].a,v,e[t].c)%md)%md;
    	else sum=(all(e[t].b,v-ss)+all(e[t].a,e[t].c)+e[e[t].a].s%md*e[t].l%md+e[e[t].a].s%md*to(e[t].b,v-ss,e[t].d)%md)%md;
    	hs[-hs1].t=t;
    	hs[-hs1].s=sum%md;
    	hs[-hs1].v=v;
    	hs[-hs1].id=tn+1;
    	return sum;
    }
    int main()
    {
    	scanf("%lld",&tn);
    	while(tn--)
    	{
    		scanf("%lld",&m);
    		e[0].s=1;
    		LL a,b,c,d;
    		for(LL i=1;i<=m;i++)
    		{
    			scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&e[i].l);
    			c++,d++;
    			e[i].a=a,e[i].b=b,e[i].c=c,e[i].d=d;
    			e[i].s=e[a].s+e[b].s;
    			ans[i]=ans[a]+ans[b]+(e[a].s%md)*(e[b].s%md)%md*e[i].l%md+e[a].s%md*all(b,d)%md+e[b].s%md*all(a,c)%md;
    			ans[i]%=md;
    			printf("%lld
    ",ans[i]);
    		}
    	}
    	return 0;
    }
    
    哈哈哈哈哈哈哈哈哈哈
  • 相关阅读:
    learning scala view collection
    scala
    learning scala dependency injection
    learning scala implicit class
    learning scala type alise
    learning scala PartialFunction
    learning scala Function Recursive Tail Call
    learning scala Function Composition andThen
    System.Threading.Interlocked.CompareChange使用
    System.Threading.Monitor的使用
  • 原文地址:https://www.cnblogs.com/LZA119/p/13910096.html
Copyright © 2011-2022 走看看