首页 > 其他分享 >球包树

球包树

时间:2023-11-13 18:46:49浏览次数:22  
标签:pre int fa fno path 包树 mod

链接:K-球包树_多比特杯武汉工程大学第六届ACM新生赛(同步赛) (nowcoder.com)

题意 :

 借鉴官方题解LCA做法

 题解中的a是我的代码中的w, w是我代码中的path(个人感觉更容易的理解)

#include<bits/stdc++.h>

using namespace std;
using ull = unsigned long long;
using ll = long long;
using PII = pair<int,int>;
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define endl "\n"
#define pb push_back
#define int long long
const int N=1e6+10;
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
int w[N];
vector<int> g[N];
int n, m;
int path[N];//path为对答案的贡献,经过的 = 穿过 + 以u为两端点的个数(恒为n)
int dep[N];
int pre[N];//每个节点到根节点路径上的path和, i到j的path贡献为prei + prej - pre(lca(i, j)) - pre(fa((lca(i, j))))
int siz[N];
int val[N];//以u为子树中所有path和
int fa[N][30];
void dfs(int u, int fno)
{
    dep[u] = dep[fno] + 1;
    siz[u] = 1;
    fa[u][0] = fno;
    for(int k = 1; k <= 25; k ++)
        fa[u][k] = fa[fa[u][k - 1]][k - 1];
    for(auto v : g[u])
    {
        if(v == fno) continue;
        dfs(v, u);
        siz[u] += siz[v];
    }
    int sum = 0;
    vector<int> sonw;//每子树那边的个数
    for(auto v : g[u])
    {
        if(v == fno) continue;
        sonw.pb(siz[v]);
    }
    sonw.pb(n - siz[u]);//只有一个父亲,父亲那边的个数
    path[u] = n;
    for(auto it : sonw)
    {
        path[u] = (path[u] + sum * it) % mod;
        sum += it;
    }
}
void dfs1(int u, int fno)
{
    pre[u] = (pre[fno] + path[u]) % mod;
    for(auto v : g[u])
    {
        if(v == fno) continue;
        dfs1(v, u);
    }
}
void dfs2(int u, int fno)
{
    val[u] = path[u];
    for(auto v : g[u])
    {
        if(v == fno) continue;
        dfs2(v, u);
        val[u] = (val[u] + val[v]) % mod;
    }
}
int lca(int a, int b)
{
    if(dep[a] < dep[b]) swap(a, b);
    for(int k = 25; k >= 0; k --)
        if(dep[fa[a][k]] >= dep[b])
            a = fa[a][k];
    if(a == b) return a;
    for(int k = 25; k >= 0; k --)
        if(fa[a][k] != fa[b][k])
            a = fa[a][k], b = fa[b][k];
    return fa[a][0];
}
signed main()
{
    IOS;
    cin >> n >> m;
    for(int i = 1; i <= n; i ++) cin >> w[i];
    for(int i = 1; i < n; i ++)
    {
        int u, v; cin >> u >> v;
        g[u].pb(v), g[v].pb(u);
    }
    dfs(1, 0);
    dfs1(1, 0);
    dfs2(1, 0);
    int res = 0;
    for(int i = 1; i <= n; i ++) res = (res + path[i] * w[i] % mod) % mod; 
    while(m --)
    {
        int op, u, v, x;
        cin >> op;
        if(op == 1)
        {
            cin >> u >> v >> x;
            int r = lca(u, v);
            int sum = ((pre[u] + pre[v] - pre[r] - pre[fa[r][0]]) % mod + mod) % mod;
            res = (res + sum * x % mod) % mod;
        }
        else if(op == 2)
        {
            int u, x; cin >> u >> x;
            res = (res + val[u] * x % mod) % mod;//不是真的去修改, 而是记录一下改动,根据题意对res的影响
        }
        else cout << res << endl;
    }
    return 0;
}

 

标签:pre,int,fa,fno,path,包树,mod
From: https://www.cnblogs.com/ZouYua/p/17829833.html

相关文章

  • P2015 二叉苹果树 背包树形dp入门
    P2015二叉苹果树-洛谷|计算机科学教育新生态(luogu.com.cn) 背包树形dp主要是用来处理可以取若干个子节点若干个情况,来实现dp转移到父节点我们令dp[x][y][i]为......