Birthday

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

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

#include<bits/stdc++.h>
#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<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#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<class T, class S> inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;}
template<class T, class S> inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;}
template<class T, class S> inline bool chkmax(T& a, S b) {return a < b ? a = b, true : false;}
template<class T, class S> 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<PII> 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

Codeforces 494D Birthday 树形dp (看题解)相关推荐

  1. 背包类树形DP 选课题解

    题目传送门; 我觉得题目给出0节点作为虚拟课程,也避免了我们要去想将若干个森林建成一棵树:将N个节点的森林建成了N+1条边的树: 其次,我们对这个题进行一个分析: 很容易想到F[x,t]表示以x为根的 ...

  2. Codeforces 596D Wilbur and Trees dp (看题解)

    一直在考虑, 每一段的贡献, 没想到这个东西能直接dp..因为所有的h都是一样的. #include<bits/stdc++.h> #define LL long long #define ...

  3. Codeforces 709E. Centroids 树形DP

    题目链接:http://codeforces.com/contest/709/problem/E 题意: 给你一棵树,你可以任删一条边和加一条边,只要使得其仍然是一棵树,输出每个点是否都能成为重心 题 ...

  4. CodeForces - 766E  (树形dp+二进制)

    C - Mahmoud and a xor trip CodeForces - 766E 补题的时候碰见的一道题目,感觉思路非常巧妙就记录下来了. 题目大意:给出n个点,每个点有一个点权,求所有路径的 ...

  5. Appleman and Tree CodeForces - 461B(树形dp)

    Appleman has a tree with n vertices. Some of the vertices (at least one) are colored black and other ...

  6. codeforces 816 E. Karen and Supermarket(树形dp)

    题目链接:http://codeforces.com/contest/816/problem/E 题意:有n件商品,每件有价格ci,优惠券di,对于i>=2,使用di的条件为:xi的优惠券需要被 ...

  7. Codeforces 1088E Ehab and a component choosing problem(树形DP)

    Codeforces 1088E Ehab and a component choosing problem(树形DP) 题意 给一棵树,要求从中选一些联通分量,使得平均联通分量重量总和最大.如果有多 ...

  8. BZOJ 2133 切割(树形DP,树上背包)大概是本题全网第一篇题解 >_<【BZOJ 修复工程】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 BZOJ 2133 切割这道题全网搜不到任何一篇题解 >_< 看评测记录也没有几个人AC- ...

  9. 【牛客每日一题】4.15 Treepath 题解(树上dfs/树形DP)

    题目链接:https://ac.nowcoder.com/acm/problem/14248 来源:牛客网 题目描述 给定一棵n个点的树,问其中有多少条长度为偶数的路径.路径的长度为经过的边的条数.x ...

最新文章

  1. 高德地图关键字搜索oc版
  2. Java 启动线程并保持
  3. JNI与底层调用-2
  4. 【数据挖掘笔记五】数据立方体技术
  5. 深圳的中学计算机课学什么时候,2018-2019年深圳中小学校历出炉 中小学校什么时候几号开学...
  6. Javascript 检测 页面是否在iframe中
  7. php post调用api,PHP(CURL)POST数据调用API简单示例
  8. Linux磁盘下面有个mpatha,Linux中如何使用vmstat命令
  9. 微信小程序的开发需要什么费用
  10. 计算机碎片整理的作用,经常做磁盘碎片整理的好处
  11. hangfire安装
  12. 后台如何暴漏IP用于前后端测试
  13. igg google
  14. Kafka设计原理——consumer rebalance概览及过程
  15. 根据ParentId生成树状结构这po事
  16. Java 关于中文乱码问题的解决方案与经验【转载】
  17. Web3 时代 传统品牌如何玩转 NFT 营销?
  18. Source Insight 4.0安装
  19. 基于Opencv快速实现人脸识别(图片识别)
  20. OS基础-四大基本特征

热门文章

  1. php 取整函数 ceil floor round intval 随笔
  2. Java线程之CompletionService批处理任务
  3. 【转载】最好女孩子概率模型
  4. Javascript -- 二叉树(查找删除功能实现)
  5. Mr.J---重拾Ajax(一)--XMLHttpRequest
  6. python基础-python函数参数为print语句时的输出
  7. Remove Duplicates from Sorted List leetcode
  8. iOS事件机制,以及不同手势使用touchesBegan等表现形式
  9. 六步实现Spring.NET 与 NHibernate 的整合
  10. STL中 set 和 multiset