Codeforces 1260F Colored Tree
题意:
给你一棵树,每个结点的颜色可能是([l_i,r_i])任一颜色,求所有可能的树的树价值总和。每棵树的价值表示所有颜色相同的两点间的距离总和。
解法:
考虑每种颜色对答案的贡献
设(v[i])表示(l_ileq Cleq r_i , g_i=(r_i-l_i+1) , P=prodlimits_{i=1}^n g_i)
(Ans_C = sumlimits_{substack{v[i]wedge v[j]}} dis(i,j)*prodlimits_{substack{k
eq iwedge k
eq j}} g_k)
(= sumlimits_{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*sumlimits_{substack{v[i]wedge v[j]}} frac{dep(i)+dep(j)-2dep(lca(i,j))}{g_ig_j})
(=P*(sumlimits_{substack{v[i]}} frac{dep(i)}{g_i}sumlimits_{substack{v[j]wedge j
eq i}} frac{1}{g_j}-2sumlimits_{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
" , ans * p % mol);
}