https://nanti.jisuanke.com/t/41403

2019沈阳网络赛D题

树形dp。一棵树,求任意两个点的距离之和。u-v和v-u算两次。两点之间的距离分为三类,模3等于0,1,2三类,最后输出这三类的总和。

第一种方法。直接累加。遍历到一个点的时候。先计算答案。答案加上所有已经遍历过得点到他的距离之和。同时该点也要加上这个值,同时要加上数量。每次先搜到底统计往下遍历的值,然后回溯的时候统计

回溯的值。因为每次只计算了之前的点到他的距离之和,所以最后的结果要乘以2,因为u-v与v-u算两次。

每次加的时候先计算当前点前一个点到他的距离,及0+该边的边权。然后在按0,1,2来累加,如果为零表示没有,就不累加。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e4 + ;
const int mod = 1e9 + ;
typedef pair<int, ll> pii;
int n;
vector<pii> g[N];
ll ans[];//结果数组
struct Node {
ll valup[];//递归回溯的时候
ll valdown[];//递归往下的时候
ll cntdown[], cntup[];//递归往下与回溯的点数量。
} node[N]; void dfs(int u, int f) {
int len = g[u].size();
for(int i = ; i < len; i++) {
int v = g[u][i].first;
ll w = g[u][i].second;
if(v == f) continue;
node[v].valdown[w%] = (node[v].valdown[w%] + w) % mod;
node[v].cntdown[w%] = (node[v].cntdown[w%] + ) % mod;
ans[w%] = (ans[w%] + w) % mod;
for(int j = ; j < ; j++) {
ll ww = (node[u].valdown[j] + node[u].valup[j]) % mod;
ll cnt = (node[u].cntdown[j] + node[u].cntup[j]) % mod;
if(ww == ) continue;
ll mo = (j + w) % ;
node[v].valdown[mo] = (node[v].valdown[mo] + ww) % mod;
node[v].valdown[mo] = (node[v].valdown[mo] + w * cnt) % mod;
node[v].cntdown[mo] = (node[v].cntdown[mo] + cnt) % mod;
ans[mo] = (ans[mo] + ww) % mod;
ans[mo] = (ans[mo] + w * cnt) % mod;
}
dfs(v, u);
node[u].valup[w%] = (node[u].valup[w%] + w) % mod;
node[u].cntup[w%] = (node[u].cntup[w%] + ) % mod;
for(int j = ; j < ; j++) {
ll ww = node[v].valup[j];
ll cnt = node[v].cntup[j];
if(ww == ) continue;
ll mo = (j + w) % ;
node[u].valup[mo] = (node[u].valup[mo] + ww) % mod;
node[u].valup[mo] = (node[u].valup[mo] + w * cnt) % mod;
node[u].cntup[mo] = (node[u].cntup[mo] + cnt) % mod;
}
}
} int main() {
while(~scanf("%d", &n)) {
int u, v;
ll w;
ans[] = ans[] = ans[] = ;
for(int i = ; i < n; i++) {
g[i].clear();
for(int j = ; j < ; j++) node[i].valup[j] = node[i].valdown[j] = node[i].cntdown[j] = node[i].cntup[j] = ;
}
for(int i = ; i < n; i++) {
scanf("%d%d%lld", &u, &v, &w);
g[u].push_back(pii(v, w));
g[v].push_back(pii(u, w));
}
dfs(, -);
for(int i = ; i < ; i++) {
printf("%lld%c", (ans[i] * ) % mod, i == ? '\n' : ' ');
}
}
return ;
}

算贡献的方法。

#include <stdio.h>
#include <string.h>
using namespace std;
#define LL long long
const int N=;
const LL MOD = 1e9 + ; int n,root;
int nex[N],tot,fir[N],to[N],len[N];
LL f[N][],g[N][],num[N][];
void build(int x,int y,int z)
{
nex[++tot]=fir[x];
fir[x]=tot;
to[tot]=y;
len[tot]=z;
} void mo(LL &x) {
x %= MOD;
if(x < ) x += MOD;
} void dfs(int x,int fa)
{
num[x][]++;
for(int i=fir[x];i;i=nex[i])
{
int y=to[i];
if(y==fa)continue;
dfs(y,x);
for(int j=;j<;++j){
g[x][(j+len[i])%]+=(num[y][j]*len[i]+g[y][j]) % MOD;
num[x][(j+len[i])%]+=num[y][j];
f[x][j] += f[y][j]; mo(num[x][(j+len[i])%]);
mo(g[x][(j + len[i]) % ]);
mo(f[x][j]);
}
}
for(int i=;i<;i++)
{
f[x][i]+=g[x][i];
mo(f[x][i]);
}
for(int i=fir[x];i;i=nex[i])
{
int y=to[i];
if(y==fa)continue;
for(int j=;j<;++j) {
int ind = (j-len[i])%;
if(ind < ) ind += ;
for(int k=;k<;++k) {
f[x][(j+k+len[i])%]+=len[i]*(num[x][j]-num[y][ind]) % MOD *num[y][k] % MOD ;
f[x][(j+k+len[i])%]+=(g[x][j] - g[y][ind] - num[y][ind] * len[i]) % MOD *num[y][k] % MOD ;
f[x][(j+k+len[i])%]+=(num[x][j]-num[y][ind])*g[y][k] % MOD;
mo(f[x][(j+k+len[i])%]);
}
}
}
} int main()
{
// freopen("a.in","r",stdin);
int n;
while (~scanf("%d",&n)) {
tot=;
memset(fir,,sizeof(fir));
memset(f,,sizeof(f));
memset(g,,sizeof(g));
memset(num,,sizeof(num));
for (int i = ;i < n;i++) {
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
x++;y++;
build(x,y,z);
build(y,x,z);
}
dfs(,);
printf("%lld %lld %lld\n",f[][],f[][],f[][]); } return ;
} /**
3
0 1 2
0 2 3
*/

2019沈阳网赛树形dp的更多相关文章

  1. HDU 6201 2017沈阳网络赛 树形DP或者SPFA最长路

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6201 题意:给出一棵树,每个点有一个权值,代表商品的售价,树上每一条边上也有一个权值,代表从这条边经过 ...

  2. 2019 沈阳网络赛 D Fish eating fruit ( 树形DP)

    题目传送门 题意:求一颗树中所有点对(a,b)的路径长度,路径长度按照模3之后的值进行分类,最后分别求每一类的和 分析:树形DP \(dp[i][j]\) 表示以 i 为根的子树中,所有子节点到 i ...

  3. 2019 沈阳网络赛 Fish eating fruit

    这题看了三个月,终于过了,第一次看的时候没学树形DP,想用点分治但是不会 后来学了二次扫描,就有点想法了.... 这东西也真就玄学了吧... #include<iostream> #inc ...

  4. 2015年沈阳网赛 Jesus Is Here(DP中的计数问题)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5459 题目描述:给定一个递推得来的字符串,问字符串中不同cff之间的距离之和, 递推规则: s1=c; ...

  5. hdu 4274 2012长春赛区网络赛 树形dp ***

    设定每个节点的上限和下限,之后向上更新,判断是否出现矛盾 #include<cstdio> #include<iostream> #include<algorithm&g ...

  6. [2019沈阳网络赛D题]Dawn-K's water(点分治)

    题目链接 题意为求出树上任意点对的距离对3取余的和. 比赛上听到题意就知道是点分治了,但是越写越不对劲,交之前就觉得会T,果不其然T了.修修改改结果队友写了发dp直接就过了Orz. 赛后想了想维护的东 ...

  7. hdu5461 Largest Point(沈阳网赛)

    Largest Point Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total ...

  8. hdu 5455 (2015沈阳网赛 简单题) Fang Fang

    题目;http://acm.hdu.edu.cn/showproblem.php?pid=5455 题意就是找出所给字符串有多少个满足题目所给条件的子串,重复的也算,坑点是如果有c,f以外的字符也是不 ...

  9. hdu 5461(2015沈阳网赛 简单暴力) Largest Point

    题目;http://acm.hdu.edu.cn/showproblem.php?pid=5461 题意就是在数组中找出a*t[i]*t[i]+b*t[j]的最大值,特别注意的是这里i和i不能相等,想 ...

随机推荐

  1. Java如何自定义注解

    本文主要是记录所学,以供后续参考.注解是Java 1.5引入的,Java自定义注解是通过运行时靠反射获取注解,注解相当于是一种嵌入在程序中的元数据,可以使用注解解析工具或编译器对其进行解析,也可以指定 ...

  2. AcWing 6. 多重背包问题 III

    //f[i,j] 所有只从前i块能量石中选,且总体积恰好为j的方案数 #include <iostream> #include <algorithm> #include < ...

  3. 数据预处理 | 使用 Pandas 进行数值型数据的 标准化 归一化 离散化 二值化

    1 标准化 & 归一化 导包和数据 import numpy as np from sklearn import preprocessing data = np.loadtxt('data.t ...

  4. 巴塞尔问题(Basel problem)的多种解法

    巴塞尔问题(Basel problem)的多种解法——怎么计算\frac{1}{1^2}+\frac{1}{2^2}+\frac{1}{3^2}+\cdots112+122+132+⋯ ? (PS:本 ...

  5. 【转载】深入理解Java虚拟机笔记---运行时栈帧结构

    栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区的虚拟机栈(Virtual Machine Stack)的栈元素.栈帧存储了方法的局部变量表,操作 ...

  6. windows安装python64位和32位的方法

    1.先安装python 64位的 python,创建一个64位的python虚拟环境: 2.再安装python 32位的 python,创建一个32位的python虚拟环境即可. 注意:两个版本安装在 ...

  7. spring boot no identifier specified for entity

    定义Id 时,引用的是 import org.springframework.data.annotation.Id;  实际应该引入: import javax.persistence.Id;

  8. Jmeter-功能概要

    1.Jmeter工具组成部分 (1)资源生成器:用于生成测试过程中服务器.负载机的资源代码.(LR中的VuGen) (2)用户运行器:通常是一个脚本运行引擎,根据脚本要求模拟指定的用户行为.(LR中的 ...

  9. jdk8-》reduce操作

    什么是reduce操作 聚合操作,中⽂意思是 “减少” 根据⼀定的规则将Stream中的元素进⾏计算后返回⼀个唯⼀的值 常⽤⽅法⼀: Optional<T> reduce(BinaryOp ...

  10. AcWing 1022. 宠物小精灵之收服 二维费用背包

    #include<iostream> using namespace std ; ; int f[N][N]; int V1,V2,n; int main() { cin>>V ...