jzoj 3844. 統計損失(count) (Standard IO)

Description
SJY有一天被LLT緊急召去計算一些可能的損失。LLT元首管理的SHB國的交通形成了一棵樹,現在將會出現一顆隕石砸在SHB國中,並且隕石砸毀的必定是SHB國構成的交通樹上的一條路徑。SHB國的損失可表示爲被砸毀的路徑上的所有城市價值之積。現在還暫時無法確定隕石的掉落路線,所以LLT元首希望SJY能夠告訴他SHB國在受到每一種砸毀方式後會受到的損失之和模10086之後的值。注意:單獨一個節點也被認爲是合法的路徑。

Input
第1行一個數n,表示城市數。
第2行n個數,第i個數表示第i個城市的價值。
第3到n+1行,每行兩個數u,v,表示城市u,v之間有一條道路。

Output
包含一個數,表示SHB國將受到的損失之和。

Sample Input
5
7 6 6 1 1
1 2
2 3
2 4
1 5

Sample Output
778

Data Constraint
對於20%的數據,n<=100;
對於50%的數據,n<=3000;
對於100%的數據,n<=100000。

//written by zzy

題目大意:

求一個樹的所有路徑積(路徑上的所有點的權值之積)

題解:

樹形dp,設f[x]f[x]爲以xx爲根的子樹的到xx的所有路徑積之和(所有直鏈到x的路徑積),
考慮如何轉移和求出答案
發現轉移很簡單,f[x]=sumw[x]f[son]f[x]=sum{ w[x]*f[son]}
f[x]f[x]不能算上折鏈(“V”形路徑)的路徑積,(因爲f[x]f[x]要層層傳上去,就不能表示兩點之間的路徑積了)
所以答案要再另外加上所有折鏈的路徑積,
考慮如何求,
其實折鏈可以看成兩條直鏈(從一個節點到xx再到另一個節點),
子樹xx到子樹yy的所有路徑積(x,y)(x,y)等於f[x]w[lca(x,y)]f[y]f[x]*w[lca(x,y)]*f[y]
但不能兩兩計算(x,y)(x,y),(時間複雜度會退化)
可以考慮當遍歷完一個子樹後將其加入f[x]f[x]中,
累記起來(相當於不斷合併子樹,邊合併邊更新答案)

#include<iostream> 
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 100005
#define Mod 10086
using namespace std;

int i,j,n,m,l,x;
long long ans;
int w[N],f[N];
bool vis[N];

int list[N],v[2*N],next[2*N];

void add(int x) {
	next[++l]=list[x];
	list[x]=l;
}

void dfs(int x) {
	f[x]=w[x];
	for (int t=list[x],y=v[t];t;t=next[t],y=v[t]) 
     if (!vis[y]) {
     	vis[y]=true; dfs(y);
     	ans=(ans+(f[x]*f[y])%Mod)%Mod;//更新答案
     	f[x]=(f[x]+(f[y]*w[x])%Mod)%Mod;//合併子樹
     }
}  

int main()
{
	scanf("%d",&n);
	for (i=1;i<=n;i++) { 
	 scanf("%d",&w[i]);
	 ans+=w[i];
    }
	for (i=1;i<=n-1;i++) {
		scanf("%d%d",&x,&v[i*2-1]); add(x);
		v[i*2]=x; add(v[i*2-1]); 
	}
	vis[1]=true;
	dfs(1);
	printf("%d",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章