球包树
链接: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; }
本文作者:zouyua
本文链接:https://www.cnblogs.com/ZouYua/p/17829833.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步