Fish eating fruit 沈阳网络赛(树形dp)
Fish eating fruit
\]
题意
大体的题意就是给出一棵树,求每一对点之间的距离,然后把该距离存在距离 \(\mod 3\) 的位置,输出总和。
思路
令两个 \(dp\) 数组和两个辅助 \(dp\) 的数组。
\(dp1[i][j]\) 表示从 \(i\) 为起点往下到各个点距离 \(\mod 3\) 后为 \(j\) 的距离总和。
\(cnt1[i][j]\) 表示以 \(i\) 为起点往下到各个点距离 \(\mod 3\) 后为 \(j\) 的节点个数。
\(dp2[i][j]\) 表示从 \(i\) 起点往上一步后到各个点距离 \(\mod 3\) 后为 \(j\) 的距离总和。
\(cnt2[i][j]\) 表示以 \(i\) 为起点往上一步后到各个点距离 \(\mod 3\) 后为 \(j\) 的节点个数。
对于两个 \(dp\) 分别跑一遍 \(dfs\)
对于 \(dp1\) 比较好处理,直接往下 \(dfs\)
以 \(u\) 开始的答案等于从 \(v\) 开始的答案加上这一条边 \(w\) 的贡献,可以得到
cnt1[u][(j+w)\%3] = \sum cnt1[v][j]
\]
对于 \(dp2\) 会比较麻烦,需要用 \(fa\) 节点向上的贡献在加上 \(fa\) 节点往下的贡献在减去 \(fa\) 节点往 \(u\) 走的贡献。这些节点就是 \(u\) 往上走一步后可以走到的所有节点。这样算出真实的节点数和距离总和,然后 \(u\) 才能开始转移。
设 \(faw\) 为从 \(u\) 到 \(fa\) 的路径长度
计算真实的节点数:
c[(j+faw)\%3] -= cnt1[u][j]
\]
计算真实的距离总和:
d[(j+faw)\%3] -= dp1[u][0]+cnt1[u][j]*faw
\]
则最后的 \(dp2\) 就可以利用 \(d\) 和 \(c\) 得到了
cnt2[u][(j+faw)\%3] = c[j]
\]
/***************************************************************
> File Name : a.cpp
> Author : Jiaaaaaaaqi
> Created Time : Mon 16 Sep 2019 08:55:33 PM CST
***************************************************************/
#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#define lowbit(x) x & (-x)
#define mes(a, b) memset(a, b, sizeof a)
#define fi first
#define se second
#define pb push_back
#define pii pair<int, int>
typedef unsigned long long int ull;
typedef long long int ll;
const int maxn = 1e5 + 10;
const int maxm = 1e5 + 10;
const ll mod = 1e9 + 7;
const ll INF = 1e18 + 100;
const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-8;
using namespace std;
int n, m;
int cas, tol, T;
vector< pii > vv[maxn];
ll cnt1[maxn][3], cnt2[maxn][3];
ll dp1[maxn][3], dp2[maxn][3];
void dfs1(int u, int fa) {
cnt1[u][0] = 1;
for(auto i : vv[u]) {
int v = i.fi, w = i.se;
if(v == fa) continue;
dfs1(v, u);
dp1[u][(0+w)%3] += (cnt1[v][0]*w%mod+dp1[v][0])%mod;
dp1[u][(1+w)%3] += (cnt1[v][1]*w%mod+dp1[v][1])%mod;
dp1[u][(2+w)%3] += (cnt1[v][2]*w%mod+dp1[v][2])%mod;
for(int j=0; j<3; j++) dp1[u][j] %= mod;
cnt1[u][(0+w)%3] += cnt1[v][0];
cnt1[u][(1+w)%3] += cnt1[v][1];
cnt1[u][(2+w)%3] += cnt1[v][2];
}
}
void dfs2(int u, int fa) {
if(u!=1) {
int faw;
for(auto i : vv[u]) {
if(i.fi == fa) {
faw = i.se;
break;
}
}
int c[3] = { 0 };
c[0] = cnt2[fa][0]+cnt1[fa][0];
c[1] = cnt2[fa][1]+cnt1[fa][1];
c[2] = cnt2[fa][2]+cnt1[fa][2];
c[(0+faw)%3] -= cnt1[u][0];
c[(1+faw)%3] -= cnt1[u][1];
c[(2+faw)%3] -= cnt1[u][2];
ll d[3] = { 0 };
d[0] = (dp2[fa][0]+dp1[fa][0])%mod;
d[1] = (dp2[fa][1]+dp1[fa][1])%mod;
d[2] = (dp2[fa][2]+dp1[fa][2])%mod;
d[(0+faw)%3] = ((d[(0+faw)%3] - (cnt1[u][0]*faw%mod+dp1[u][0])%mod+mod)%mod+mod)%mod;
d[(1+faw)%3] = ((d[(1+faw)%3] - (cnt1[u][1]*faw%mod+dp1[u][1])%mod+mod)%mod+mod)%mod;
d[(2+faw)%3] = ((d[(2+faw)%3] - (cnt1[u][2]*faw%mod+dp1[u][2])%mod+mod)%mod+mod)%mod;
dp2[u][(0+faw)%3] = (c[0]*faw%mod+d[0])%mod;
dp2[u][(1+faw)%3] = (c[1]*faw%mod+d[1])%mod;
dp2[u][(2+faw)%3] = (c[2]*faw%mod+d[2])%mod;
cnt2[u][(0+faw)%3] += c[0];
cnt2[u][(1+faw)%3] += c[1];
cnt2[u][(2+faw)%3] += c[2];
}
for(auto i : vv[u]) {
int v = i.fi, w = i.se;
if(v == fa) continue;
dfs2(v, u);
}
}
int main() {
// freopen("in", "r", stdin);
while(~scanf("%d", &n)) {
for(int i=1; i<=n; i++) {
vv[i].clear();
}
mes(dp1, 0), mes(dp2, 0);
mes(cnt1, 0), mes(cnt2, 0);
for(int i=1, u, v, w; i<n; i++) {
scanf("%d%d%d", &u, &v, &w);
u++, v++;
vv[u].pb(make_pair(v, w));
vv[v].pb(make_pair(u, w));
}
dfs1(1, 0);
dfs2(1, 0);
// for(int i=1; i<=n; i++) {
// for(int j=0; j<3; j++) {
// printf("dp1[%d][%d] = %lld, cnt1[%d][%d] = %lld\n", i, j, dp1[i][j], i, j, cnt1[i][j]);
// }
// }
// cout << "-----------------" << endl;
// for(int i=1; i<=n; i++) {
// for(int j=0; j<3; j++) {
// printf("dp2[%d][%d] = %lld, cnt2[%d][%d] = %lld\n", i, j, dp2[i][j], i, j, cnt2[i][j]);
// }
// }
ll ans0, ans1, ans2;
ans0 = ans1 = ans2 = 0;
for(int i=1; i<=n; i++) {
ans0 = (ans0+dp1[i][0]+dp2[i][0])%mod;
ans1 = (ans1+dp1[i][1]+dp2[i][1])%mod;
ans2 = (ans2+dp1[i][2]+dp2[i][2])%mod;
}
printf("%lld %lld %lld\n", ans0, ans1, ans2);
}
return 0;
}
Fish eating fruit 沈阳网络赛(树形dp)的更多相关文章
- HDU 6201 2017沈阳网络赛 树形DP或者SPFA最长路
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6201 题意:给出一棵树,每个点有一个权值,代表商品的售价,树上每一条边上也有一个权值,代表从这条边经过 ...
- 2019沈阳网赛树形dp
https://nanti.jisuanke.com/t/41403 2019沈阳网络赛D题 树形dp.一棵树,求任意两个点的距离之和.u-v和v-u算两次.两点之间的距离分为三类,模3等于0,1,2 ...
- hdu 4274 2012长春赛区网络赛 树形dp ***
设定每个节点的上限和下限,之后向上更新,判断是否出现矛盾 #include<cstdio> #include<iostream> #include<algorithm&g ...
- 2018 ICPC 沈阳网络赛
2018 ICPC 沈阳网络赛 Call of Accepted 题目描述:求一个算式的最大值与最小值. solution 按普通算式计算方法做,只不过要同时记住最大值和最小值而已. Convex H ...
- 2019 沈阳网络赛 D Fish eating fruit ( 树形DP)
题目传送门 题意:求一颗树中所有点对(a,b)的路径长度,路径长度按照模3之后的值进行分类,最后分别求每一类的和 分析:树形DP \(dp[i][j]\) 表示以 i 为根的子树中,所有子节点到 i ...
- 2019 沈阳网络赛 Fish eating fruit
这题看了三个月,终于过了,第一次看的时候没学树形DP,想用点分治但是不会 后来学了二次扫描,就有点想法了.... 这东西也真就玄学了吧... #include<iostream> #inc ...
- The Preliminary Contest for ICPC Asia Shenyang 2019 D. Fish eating fruit(树形dp)
题意:求一棵树上所有路径和模3分别为0 1 2 的权值的和 思路:树形dp 增加一个记录儿子节点满足条件的个数的数组 不要放在一起dp不然答案跟新会有问题 #include <bits/stdc ...
- 5.21 省选模拟赛 luogu P4297 [NOI2006]网络收费 树形dp
LINK:网络收费 还是自己没脑子. 早上思考的时候 发现树形dp不可做 然后放弃治疗了. 没有合理的转换问题的模型是我整个人最大的败笔. 暴力也值得一提 爆搜之后可以写成FFT的形式的计算贡献的方法 ...
- 沈阳网络赛 F - 上下界网络流
"Oh, There is a bipartite graph.""Make it Fantastic." X wants to check whether a ...
随机推荐
- .NET Core:跨域
在Startup中的ConfigureServices方法中配置:services.AddCors(options => options.AddPolicy("any", b ...
- python运维开发常用模块(四)文件对比模块difflib
1.difflib介绍 difflib作为 Python的标准库模块,无需安装,作用是对比文本之间的差异,且支持 输出可读性比较强的HTML文档,与Linux下的diff命令相似.我们可以 使用dif ...
- 论文阅读: Building a 3-D Line-Based Map Using Stereo SLAM
Abstract 一个把直线用作feature的SLAM系统. 跟点相比, 直线对于环境的结构提供了更丰富的信息, 也让其鞥有可能推断地图的空间语义. 使用了Plucker line coordian ...
- SQL --------------- between 和< >
between值 and 值 运算符用于选取介于两个值之间的数据范围内的值,常与where一块使用between运算符选择给定范围内的值.值可以是数字,文本或日期. 使用between的时候会与and ...
- MarkDown的一些基本语法
Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式. Markdown的语法简洁明了.学习容易,而且功能比纯文本更强,因此有很多人用它写 ...
- redux的本质是一套行为解释系统
redux的本质是一套行为解释系统. 首先构建解释系统: 然后使用解释系统对行为进行解释,进而完成对store和状态的维护.
- 【ELK】7. elasticsearch linux上操作es命令详解
========== 1.检查ES节点是否正常启动 curl http://192.168.6.16:9200 正常状态: 非正常状态: 1>确保服务是不是正常启动了,端口用的是哪个 2> ...
- Linux学习笔记之AIX系统上压缩与解压文件
0x00 概述 AIX机器真难用,一时半会还真适应不了. 0x01 压缩tar 命令格式: # tar -cvf (或xvf)+文件名+设备 C:是本地到其他设备 x:是其他设备到本地 r:是追加 ...
- Reactor的NIO线程模型
1.Reactor单线程模型 传统的javaNIO通信的线程模型.该线程模型仅有一个I/O线程处理所有的I/O操作,如下图: 单线程模型的Reactor 所有的客户端都连接到一个I/O线程负责的A ...
- 一般处理程序Session
1.要在一般处理程序中获取其他页面的session值,需要引用名空间: using System.Web.SessionState; 2.然后继承一个接口:IRequiresSessionState ...