1. 程式人生 > 實用技巧 >CF960E Alternating Tree 點分治

CF960E Alternating Tree 點分治

很久沒寫點分治了 十分拉跨 寫了一下午
首先我們觀察題目 如果一條路徑的點數為偶數 那麼這條路徑是無效的 因為一正一反求和恰好為0
而如果為奇數的話 就得*2
那麼問題轉換成了 求一棵樹 所有點數為奇數的路徑權值和(權值的計算方法就是他給的方法)
點分治搞一下就行
另外關於點分治的一些細節:如果算邊權的話比較好寫 如果是算點權的話 可以先把被分治的點拿出來 單獨計算(類似於算邊權)

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+100;
typedef long long ll;
const ll mod = 1e9+7;
const int inf = 1e9;
ll val[N],op[2],ct[2],ans;
int n,_size,mx,rt;
int cur,h[N],nex[N<<1],to[N<<1],siz[N],vis[N];
void add_edge(int x,int y){
	to[++cur]=y;nex[cur]=h[x];h[x]=cur;
}
void getrt(int u,int fa){
	siz[u]=1;
	int num=0;
	for(int i = h[u]; i; i = nex[i]){
		int v = to[i];
		if(v==fa||vis[v]) continue;
		getrt(v,u);
		siz[u]+=siz[v];
		if(siz[v]>num) num=siz[v];
	}
	if(_size-siz[u]>num) num=_size-siz[u];
	if(num<mx)  mx=num,rt=u;
}
void cal(int u,int fa,int dep,ll nowsum,ll add){
	if(dep){
		nowsum=(nowsum+val[u])%mod;
		ans=(ans+(ct[dep]*(nowsum-add+mod)%mod+op[dep])%mod)%mod;
	}else{
		nowsum=(nowsum-val[u]+mod)%mod;
		ans=(ans+(ct[dep]*(-nowsum+add+mod)%mod-op[dep]+mod)%mod)%mod;
	}
	for(int i = h[u]; i; i = nex[i]){
		int v = to[i];
		if(v==fa||vis[v]) continue;
		cal(v,u,dep^1,nowsum,add);
	}
}
void ins(int u,int fa,int dep,ll s){
	if(dep) s=(s+val[u])%mod;
	else s=(s-val[u]+mod)%mod;
	ct[dep]++;
	op[dep]=(op[dep]+s)%mod;
	for(int i = h[u]; i; i = nex[i]){
		int v = to[i];
		if(v==fa||vis[v]) continue;
		ins(v,u,dep^1,s);
	}
}
void divide(int u){
	vis[u]=1;
	op[0]=0;
	op[1]=0;
	ct[0]=1,ct[1]=0;
	for(int i = h[u]; i; i = nex[i]){
		int v = to[i];
		if(vis[v]) continue;
		cal(v,u,1,0,val[u]);
		ins(v,u,1,0);
	}
	for(int i = h[u]; i; i = nex[i]){
		int v = to[i];
		if(vis[v]) continue;
		_size=siz[v];
		mx=inf;
		getrt(v,u);
		divide(rt);
	}
}
int main(){
	scanf("%d",&n);
	for(int i = 1; i <= n; i++) scanf("%lld",&val[i]),val[i]=(val[i]+mod)%mod;
	for(int i = 1; i < n; i++){
		int x,y;
		scanf("%d%d",&x,&y);
		add_edge(x,y);
		add_edge(y,x); 
	}
	_size=n;
	mx=inf;
	getrt(1,0);
	divide(rt);
	ans=(ans*2ll)%mod;
	for(int i = 1; i <= n; i++) ans=(ans+val[i])%mod;
	printf("%lld\n",ans);
	return 0;
} 
/*
4
1 2 3 4
1 2
2 3
3 4
*/