BZOJ3697:采药人的路径(点分治)
Description
采药人的药田是一个树状结构,每条路径上都种植着同种药材。
采药人以自己对药材独到的见解,对每种药材进行了分类。大致分为两类,一种是阴性的,一种是阳性的。
采药人每天都要进行采药活动。他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径。采药工作是很辛苦的,所以他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的。他想知道他一共可以选择多少种不同的路径。
Input
第1行包含一个整数N。
接下来N-1行,每行包含三个整数a_i、b_i和t_i,表示这条路上药材的类型。
Output
输出符合采药人要求的路径数目。
Sample Input
1 2 0
3 1 1
2 4 0
5 2 0
6 3 1
5 7 1
Sample Output
Solution
用g[i][0…1],f[i][0…1]分别表示
前面几个子树以及当前子树路径长度和为i的路径数目
0和1用于区分路径上是否存在前缀和为i的节点(也就是可以设立中转站的节点)
那么当前子树的贡献就是f[0][0] * g[0][0] + Σf [i][0] * g [-i][1] + f[i][1] * g[-i][0] + f[i][1] * g[-i][1],
其中i的范围[-d,d],d为当前子树的深度。
Code
#include<iostream>
#include<cstring>
#include<cstdio>
#define N (200000+100)
using namespace std;
struct node
{
int to,next,len;
} edge[N*];
int n,k,sum,root,INF;
long long ans,g[N][],f[N][];
int t[N*];
int head[N],num_edge,max_depth;
int depth[N],d[N],size[N],maxn[N],dis[N];
bool vis[N]; void add(int u,int v,int l)
{
edge[++num_edge].to=v;
edge[num_edge].len=l;
edge[num_edge].next=head[u];
head[u]=num_edge;
} void Get_root(int x,int fa)
{
size[x]=;
maxn[x]=;
for (int i=head[x]; i!=; i=edge[i].next)
if (!vis[edge[i].to] && edge[i].to!=fa)
{
Get_root(edge[i].to,x);
size[x]+=size[edge[i].to];
maxn[x]=max(maxn[x],size[edge[i].to]);
}
maxn[x]=max(maxn[x],sum-size[x]);
if (maxn[x]<maxn[root]) root=x;
} void Calc(int x,int fa)
{
max_depth=max(max_depth,depth[x]);
if (t[dis[x]]) f[dis[x]][]++;
else f[dis[x]][]++;
t[dis[x]]++;
for (int i=head[x]; i!=; i=edge[i].next)
if (edge[i].to!=fa && !vis[edge[i].to])
{
depth[edge[i].to]=depth[x]+;
dis[edge[i].to]=dis[x]+edge[i].len;
Calc(edge[i].to,x);
}
t[dis[x]]--;
} void Solve(int x)
{
vis[x]=true;
g[n][]=;//关于这里为什么初始化为1的问题,想了好久,最后还是学姐给我的解答
//http://blog.csdn.net/wu_tongtong/article/details/79428928
//可能路径是从当前树根到某一个节点的时候,路径已经平衡,不需要去另一个子树里面找另一个链拼接了
//所以这一部分的答案也要统计进去。
int up=;
for (int i=head[x]; i!=; i=edge[i].next)
if (!vis[edge[i].to])
{
depth[edge[i].to]=;
dis[edge[i].to]=edge[i].len+n;
max_depth=;
Calc(edge[i].to,);
up=max(up,max_depth); ans+=(g[n][]-)*f[n][];
for (int j=-max_depth; j<=max_depth; ++j)
ans+=g[n-j][]*f[n+j][]+g[n-j][]*f[n+j][]+g[n-j][]*f[n+j][];
for (int j=-max_depth; j<=max_depth; ++j)
{
g[n-j][]+=f[n-j][];
g[n-j][]+=f[n-j][];
f[n-j][]=f[n-j][]=;
}
}
for (int i=-up; i<=up; ++i)
g[n-i][]=g[n-i][]=;
for (int i=head[x]; i!=; i=edge[i].next)
if (!vis[edge[i].to])
{
sum=size[edge[i].to];
root=;
Get_root(edge[i].to,);
Solve(root);
}
} int main()
{
int u,v,l;
scanf("%d",&n);
sum=maxn[]=n;
for (int i=; i<=n-; ++i)
{
scanf("%d%d%d",&u,&v,&l);
add(u,v,l==?-:);
add(v,u,l==?-:);
}
Get_root(,);
Solve(root);
printf("%lld",ans);
}
BZOJ3697:采药人的路径(点分治)的更多相关文章
- BZOJ3697采药人的路径——点分治
题目描述 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动.他选择的路径 ...
- [bzoj3697]采药人的路径——点分治
Brief Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天 ...
- 【BZOJ3697】采药人的路径 点分治
[BZOJ3697]采药人的路径 Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是 ...
- [bzoj3697]采药人的路径_点分治
采药人的路径 bzoj-3697 题目大意:给你一个n个节点的树,每条边分为阴性和阳性,求满足条件的链的个数,使得这条链上阴性的边的条数等于阳性的边的条数,且这条链上存在一个节点,这个节点到一个端点的 ...
- bzoj千题计划248:bzoj3697: 采药人的路径
http://www.lydsy.com/JudgeOnline/problem.php?id=3697 点分治 路径0改为路径-1 g[i][0/1] 和 f[i][0/1]分别表示当前子树 和 已 ...
- BZOJ3697 采药人的路径 【点分治】
题目 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天都要进行采药活动.他选择的路径 ...
- BZOJ3697: 采药人的路径(点分治)
Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动 ...
- 2019.01.09 bzoj3697: 采药人的路径(点分治)
传送门 点分治好题. 题意:给出一棵树,边分两种,求满足由两条两种边数相等的路径拼成的路径数. 思路: 考虑将边的种类转化成边权−1-1−1和111,这样就只用考虑由两条权值为000的路径拼成的路径数 ...
- BZOJ 3697/3127 采药人的路径 (点分治)
题目大意: 从前有一棵无向树,树上边权均为$0$或$1$,有一个采药人,他认为如果一条路径上边权为$0$和$1$的边数量相等,那么这条路径阴阳平衡.他想寻找一条合法的采药路径,保证阴阳平衡.然后他发现 ...
随机推荐
- TypeScript 乱糟笔记
数组头上插一个值. var arr: Array<String> = ['a', 'b', 'c'];arr.unshift('d'); object删除元素. var obj: Obje ...
- Lambda表达式&匿名方法
“Lambda表达式“(lambda Expression)就是一个匿名函数(匿名方法),lambda表达式基于数学中的入演算得名. lambda运算符:所有的lambda表达式都是用新的lambda ...
- 你所需要的sql数据库资料
sql语法的特点 1.没有"",所有的字符串都使用''包含 2.它的逻辑相等与赋值运算符一样都是= 如 if 1=1 3.不区别大小写,但是习惯函数上使用大写.所有与数据库 ...
- [linux] shell脚本编程-ubuntu创建vsftpd服务
1. useradd -s /bin/bash -m 用户名 , 创建用户,自动创建家目录 , 设置登录shell 2. echo 用户名:密码 | chpasswd ,非交互式设置密码 3. ...
- Java面试宝典之----java基础(含答案)
一 JAVA基础 1. JAVA中的几种基本数据类型是什么,各自占用多少字节. int 32bit short 16bitlong 64bit byte 8b ...
- 循环遍历正则验证input框内容合法性
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Zookeeper Curator API 使用
0. 原生 ZOOKEEPER JAVA API http://www.cnblogs.com/rocky-fang/p/9030438.html 1. 概述 Curator采用cache封装对事件 ...
- 有标号的DAG计数系列问题
传送门 II 设 \(f_i\) 表示 \(i\) 个点的答案 那么枚举至少 \(j\) 个点的出度为 \(0\) \[\sum_{j=0}^{i}(-1)^j\binom{i}{j}f_{i-j}2 ...
- SPOJ:NSUBSTR - Substrings
题面 字符串$ S \(最多包含\) 25 \(万个小写拉丁字母.我们将\) F(x) \(定义为长度为\) x \(的某些字符串出现在\) s \(中的最大次数.例如,对于字符串\) "a ...
- JS上传图片转化成Base64编码demo
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...