Embiid  

Codeforces 1260F Colored Tree

题意:

给你一棵树,每个结点的颜色可能是\([l_i,r_i]\)任一颜色,求所有可能的树的树价值总和。每棵树的价值表示所有颜色相同的两点间的距离总和。

解法:

考虑每种颜色对答案的贡献
\(v[i]\)表示\(l_i\leq C\leq r_i , g_i=(r_i-l_i+1) , P=\prod\limits_{i=1}^n g_i\)
\(Ans_C = \sum\limits_{\substack{v[i]\wedge v[j]}} dis(i,j)*\prod\limits_{\substack{k\neq i\wedge k\neq j}} g_k\)
\(= \sum\limits_{\substack{v[i]\wedge v[j]}} dis(i,j)* \frac{P}{g_ig_j}\)
\(其中dis(i,j)=dep(i)+dep(j)-2dep(lca(i,j))\)
所以\(Anc_C=P*\sum\limits_{\substack{v[i]\wedge v[j]}} \frac{dep(i)+dep(j)-2dep(lca(i,j))}{g_ig_j}\)
\(=P*(\sum\limits_{\substack{v[i]}} \frac{dep(i)}{g_i}\sum\limits_{\substack{v[j]\wedge j\neq i}} \frac{1}{g_j}-2\sum\limits_{\substack{v[i]\wedge v[j]}} \frac{2dep(lca(i,j))}{g_ig_j})\)
前半段很好维护。对于后半段,添加一个点x进入,就将1-x这条路径上的值加上\(\frac{1}{g_x}\),而增加的答案是1-x这条路径原来的结点和乘上\(\frac{1}{g_x}\)

比如我们插入一个点3,将3到1的路径每个点加上\(\frac{1}{g_3}\),再插入一个点2,统计答案时就会加上1-2路径上的结点和,而这条路径上的结点和此时就是\(dep(lca(2,3))*\frac{1}{g_3}\)

删除同理,做的时候考虑减去1这个点的贡献,因为节点数=dep+1。这样用树链剖分加上数据结构维护就可以。

#include <bits/stdc++.h>
#define lson rt << 1
#define rson rt << 1 | 1
#define ll long long
using namespace std;
const int maxn = 1e5;
const ll mol = 1e9 + 7;

int tot = 0;
int n;
int id[maxn + 11],top[maxn + 11],f[maxn + 11],son[maxn + 11],siz[maxn + 11],dep[maxn + 11];
ll tree[4 * maxn + 11],lazy[4 * maxn + 11];
ll g[maxn + 11];
vector <int> edge[maxn + 11],in[maxn + 11],out[maxn + 11];

ll qpow(ll a,ll b) {
	ll ans = 1;
	while (b) {
		if (b & 1) ans = ans * a % mol;
		a = a * a % mol;
		b >>= 1;
	}
	return ans;
}

void dfs(int x,int fa) {
	siz[x] = 1;
	f[x] = fa;
	for (auto v : edge[x]) {
		if (v == fa) continue;
		dep[v] = dep[x] + 1;
		dfs(v , x);
		siz[x] += siz[v];
		if (siz[v] > siz[son[x]]) son[x] = v;
	} 
} 

void dfs2(int x,int fa,int t) {
	top[x] = t;
	id[x] = ++tot;
	if (son[x]) dfs2(son[x] , x , t);
	for (auto v : edge[x]) {
		if (v == fa || v == son[x]) continue;
		dfs2(v , x , v);
	} 
} 

ll add(ll a,ll b) { a += b; if (a >= mol) a -= mol; return a; }
ll sub(ll a,ll b) { a -= b; if (a < 0) a += mol; return a; }
void push_up(int rt) { tree[rt] = add(tree[lson] , tree[rson]); }
void push_down(int rt,int l,int r) {
	int mid = (l + r) >> 1;
	ll val = lazy[rt]; lazy[rt] = 0;
	tree[lson] = add(tree[lson] , val * (mid - l + 1) % mol); lazy[lson] = add(lazy[lson] , val);
	tree[rson] = add(tree[rson] , val * (r - mid) % mol); lazy[rson] = add(lazy[rson] , val);
}

void update(int rt,int l,int r,int al,int ar,ll val) {
	if (l > ar || r < al) return;
	if (l >= al && r <= ar) {
		tree[rt] = add(tree[rt] , val * (r - l + 1) % mol);
		lazy[rt] = add(lazy[rt] , val);
		return;
	}
	if (lazy[rt]) push_down(rt , l , r);
	int mid = (l + r) >> 1;
	update(lson , l , mid , al , ar , val);
	update(rson , mid + 1 , r , al , ar , val);
	push_up(rt);
} 

void update(int x,ll val) {
	while (x) {
		update(1 , 1 , n , id[top[x]] , id[x] , val);
		x = f[top[x]];
	}
} 

ll query(int rt,int l,int r,int al,int ar) {
	if (l > ar || r < al) return 0;
	if (l >= al && r <= ar) return tree[rt];
	if (lazy[rt]) push_down(rt , l , r);
	int mid = (l + r) >> 1;
	return add(query(lson , l , mid , al , ar) , query(rson , mid + 1 , r , al , ar));
}

ll query(int x) {
	ll ans = 0;
	while (x) {
		ans = add(ans , query(1 , 1 , n , id[top[x]] , id[x]));
		x = f[top[x]];
	}
	return ans;
}

int main(){
	scanf("%d" , &n);
	int m = 0;
	ll p = 1;
	for (int i = 1; i <= n; i++) {
		int l,r;
		scanf("%d %d",&l , &r);
		g[i] = qpow(r - l + 1 , mol - 2);
		p = p * (r - l + 1) % mol;
		m = max(m , r);
		in[l].emplace_back(i);
		out[r + 1].emplace_back(i);
	} 
	for (int i = 1; i < n; i++) {
		int u,v;
		scanf("%d %d",&u,&v);
		edge[u].emplace_back(v);
		edge[v].emplace_back(u);
	}
	dfs(1 , 0);
	dfs2(1 , 0 , 1);
	ll ans = 0;
	ll last = 0;
	ll sumg = 0;
	ll sumd = 0;
	for (int i = 1; i <= m; i++) {
		for (auto x : out[i]) {
			last = sub(last , g[x] * dep[x] % mol * sub(sumg , g[x]) % mol);
			last = sub(last , sub(sumd , g[x] * dep[x] % mol) * g[x] % mol);
			sumg = sub(sumg , g[x]);
			sumd = sub(sumd , g[x] * dep[x] % mol);
			update(x , sub(0 , g[x]));
			last = add(last , 2 * sub(query(x) , query(1)) % mol * g[x] % mol);
		}
		for (auto x : in[i]) {
			last = add(last , g[x] * dep[x] % mol * sumg % mol);
			last = add(last , sumd * g[x] % mol);
			sumg = add(sumg , g[x]);
			sumd = add(sumd , g[x] * dep[x] % mol);
			last = sub(last , 2 * sub(query(x) , query(1)) % mol * g[x] % mol);
			update(x , g[x]);
		} 
		ans = add(ans , last);
	} 
	printf("%lld\n" , ans * p % mol);
} 

posted on 2020-02-07 14:48  Embiid  阅读(168)  评论(0编辑  收藏  举报