Codeforces 1260F Colored Tree

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);
} 

猜你喜欢

转载自www.cnblogs.com/Embiid/p/12273022.html