博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Codeforces 494D Birthday 树形dp (看题解)
阅读量:4650 次
发布时间:2019-06-09

本文共 3570 字,大约阅读时间需要 11 分钟。

没想到平方和能在树上dp出来的。。。

知道了如何转移, 那么就很好写了。。。

#include
#define LL long long#define LD long double#define ull unsigned long long#define fi first#define se second#define mk make_pair#define PLL pair
#define PLI pair
#define PII pair
#define SZ(x) ((int)x.size())#define ALL(x) (x).begin(), (x).end()#define fio ios::sync_with_stdio(false); cin.tie(0);using namespace std;const int N = 1e5 + 7;const int inf = 0x3f3f3f3f;const LL INF = 0x3f3f3f3f3f3f3f3f;const int mod = 1e9 + 7;const double eps = 1e-8;const double PI = acos(-1);template
inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;}template
inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;}template
inline bool chkmax(T& a, S b) { return a < b ? a = b, true : false;}template
inline bool chkmin(T& a, S b) { return a > b ? a = b, true : false;}int n, q;int pa[N][20], len[N][20], depth[N];int allDis2[N];vector
G[N];struct dpNode { dpNode() {cnt = sumDis = sumDis2 = 0;} dpNode(int cnt, int sumDis, int sumDis2) : cnt(cnt), sumDis(sumDis), sumDis2(sumDis2) {} int cnt, sumDis, sumDis2; void print() { printf("cnt: %d sumDis: %d sumDis2: %d\n", cnt, sumDis, sumDis2); }} dp[N], dp2[N], INIT(1, 0, 0);dpNode mergeTwo(dpNode a, dpNode b, int w, int op) { if(op > 0) { a.cnt += b.cnt; add(a.sumDis, b.sumDis); add(a.sumDis, 1LL * b.cnt * w % mod); add(a.sumDis2, b.sumDis2); add(a.sumDis2, 1LL * b.sumDis * 2 * w % mod); add(a.sumDis2, 1LL * w * w % mod * b.cnt % mod); } else { a.cnt -= b.cnt; sub(a.sumDis, b.sumDis); sub(a.sumDis, 1LL * b.cnt * w % mod); sub(a.sumDis2, b.sumDis2); sub(a.sumDis2, 1LL * b.sumDis * 2 * w % mod); sub(a.sumDis2, 1LL * w * w % mod * b.cnt % mod); } return a;}void dfs(int u, int fa, int disTofa) { depth[u] = depth[fa] + 1; pa[u][0] = fa; len[u][0] = disTofa; dp[u].cnt = 1; for(int i = 1; i < 20; i++) { pa[u][i] = pa[pa[u][i - 1]][i - 1]; len[u][i] = (len[u][i - 1] + len[pa[u][i - 1]][i - 1]) % mod; } for(auto &e : G[u]) { int v = e.se; if(v == fa) continue; dfs(v, u, e.fi); dp[u] = mergeTwo(dp[u], dp[v], e.fi, 1); }}PII getLca(int u, int v) { if(depth[u] < depth[v]) swap(u, v); int dis = depth[u] - depth[v]; int ret = 0; for(int i = 19; i >= 0; i--) if(dis >> i & 1) add(ret, len[u][i]), u = pa[u][i]; if(u == v) return mk(ret, u); for(int i = 19; i >= 0; i--) { if(pa[u][i] != pa[v][i]) { add(ret, len[u][i]); add(ret, len[v][i]); u = pa[u][i]; v = pa[v][i]; } } add(ret, len[u][0]); add(ret, len[v][0]); return mk(ret, pa[u][0]);}void dfs2(int u, int fa, dpNode up) { dp2[u] = up; dp2[u].cnt--; allDis2[u] = (dp[u].sumDis2 + up.sumDis2) % mod; for(auto &e : G[u]) { if(e.se == fa) continue; up = mergeTwo(up, dp[e.se], e.fi, 1); } for(auto &e : G[u]) { if(e.se == fa) continue; up = mergeTwo(up, dp[e.se], e.fi, -1); dfs2(e.se, u, mergeTwo(INIT, up, e.fi, 1)); up = mergeTwo(up, dp[e.se], e.fi, 1); }}int main() { scanf("%d", &n); for(int i = 1; i < n; i++) { int u, v, w; scanf("%d%d%d", &u, &v, &w); G[u].push_back(mk(w, v)); G[v].push_back(mk(w, u)); } dfs(1, 0, 0); dfs2(1, 0, INIT); scanf("%d", &q); while(q--) { int u, v; scanf("%d%d", &u, &v); PII ret = getLca(u, v); int lca = ret.se, dis = ret.fi; int ans = 0; if(lca != v) { int x = mergeTwo(INIT, dp[v], dis, 1).sumDis2; int z = allDis2[u]; ans = ((2 * x - z) % mod + mod) % mod; } else { int y = mergeTwo(INIT, dp2[v], dis, 1).sumDis2; int z = allDis2[u]; ans = ((z - 2 * y) % mod + mod) % mod; } printf("%d\n", ans); } return 0;}/**/

 

转载于:https://www.cnblogs.com/CJLHY/p/10988592.html

你可能感兴趣的文章
安全发布的模式
查看>>
python的N个小功能(更新文件)
查看>>
【bzoj 4390】 [Usaco2015 dec]Max Flow(树上差分)
查看>>
FPGA内部硬件结构简介
查看>>
前端开发面试题总结-代码篇
查看>>
javaweb学习总结(三十一)——国际化(i18n)
查看>>
23种设计模式[1]:单例模式
查看>>
好的学习材料
查看>>
【DRF分页】
查看>>
6.1 文件对象常用方法与属性
查看>>
排列组合问题
查看>>
小知识点
查看>>
【笔记】HybridApp中使用Promise化的JS-Bridge
查看>>
模拟赛 sutoringu
查看>>
hdu 1253 胜利大逃亡 (广搜)
查看>>
华为上机试---购物单(算法:背包问题)
查看>>
PHP操作Mongodb API 及使用类 封装好的MongoDB操作类
查看>>
PHP实现经典算法
查看>>
NodeJS(四)Mac下如何安装package.json里面会产生依赖项
查看>>
MapReduce会自动忽略文件夹下的.开头的文件
查看>>