[BZOJ 3697] 采药人的路径
[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=3697
[算法]
首先 , 将黑色的边变成1 ,白色的边变成-1
那么 , 问题就转化为了有多少条路径满足 :
1. 路径长度为0
2. 路径中间存在一个点使得这个点可以将这条路径分成两段且长度为0
考虑我们已经处理完了前面的子树 , 对于当前子树中一点x , 深度为d , 显然 , 前面的子树中要有一个深度为-d的点y ,这条路径合法当且仅当x到分治重心的路径上有一点满足d[z] = d[x]或y到分治重心的路径上有一点满足d[z] = d[y]
那么我们可以记s[i][0 / 1]表示前面的子树中深度为i ,不存在/存在它到当前分治重心路径上的一个点,使得它的深度= i的点的个数
考虑对于当前深度为d的点x,显然至少有s[−d][1]个点会和x形成一条合法的路径。 如果分治重心到x的路径上存在一个深度为d的点,那么还会有s[−d][0]个点会和x形成一条合法路径。
详见代码 , 时间复杂度 : O(NlogN)
[代码]
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200010
typedef long long LL;
const int inf = 2e9; struct edge
{
int to , w , nxt;
} e[MAXN << ]; int n , tot , root , len;
int head[MAXN] , size[MAXN] , weight[MAXN] , cnt[MAXN << ];
int s[MAXN << ][];
bool visited[MAXN];
LL ans; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> inline void read(T &x)
{
T f = ; x = ;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = (x << ) + (x << ) + c - '';
x *= f;
}
inline void addedge(int u,int v,int w)
{
tot++;
e[tot] = (edge){v , w , head[u]};
head[u] = tot;
}
inline void getroot(int u , int fa , int total)
{
weight[u] = ;
size[u] = ;
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to;
if (v == fa || visited[v]) continue;
getroot(v , u , total);
size[u] += size[v];
chkmax(weight[u] , size[v]);
}
chkmax(weight[u] , total - size[u]);
if (weight[u] < weight[root]) root = u;
}
inline void calc(int u , int fa , int dep)
{
ans += s[n - dep][];
if (cnt[n + dep] > ) ans += s[n - dep][];
if (dep == && cnt[n] > ) ++ans;
++cnt[n + dep];
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to , w = e[i].w;
if (v == fa || visited[v]) continue;
calc(v , u , dep + w);
}
--cnt[n + dep];
}
inline void update(int u , int fa , int dep)
{
++s[n + dep][cnt[n + dep] > ];
++cnt[n + dep];
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to , w = e[i].w;
if (v == fa || visited[v]) continue;
update(v , u , dep + w);
}
--cnt[n + dep];
}
inline void clear(int u , int fa , int dep)
{
size[u] = ;
--s[n + dep][cnt[n + dep] > ];
++cnt[n + dep];
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to , w = e[i].w;
if (v == fa || visited[v]) continue;
clear(v , u , dep + w);
size[u] += size[v];
}
--cnt[n + dep];
}
inline void work(int u)
{
visited[u] = true;
cnt[n] = ;
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to , w = e[i].w;
if (visited[v]) continue;
calc(v , u , w);
update(v , u , w);
}
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to , w = e[i].w;
if (visited[v]) continue;
clear(v , u , w);
}
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to;
if (visited[v]) continue;
root = ;
getroot(v , , size[v]);
work(root);
}
} int main()
{ read(n);
for (int i = ; i < n; i++)
{
int u , v , w;
read(u); read(v); read(w);
w = (w == ) ? - : ;
addedge(u , v , w);
addedge(v , u , w);
}
weight[root = ] = inf;
getroot( , , n);
work(root);
printf("%lld\n",ans); return ; }
[BZOJ 3697] 采药人的路径的更多相关文章
- BZOJ 3697: 采药人的路径 [点分治] [我想上化学课]
传送门 题意: 路径有$-1,1$两种权值,求有多少路径满足权值和为$0$且有一个点将路径分成权值和为$0$的两段 第四节课本来想去上化学,然后快上课了这道题还没调出来.....可恶我想上化学 昨天两 ...
- bzoj 3697: 采药人的路径【点分治】
点分治,设当前处理的块的重心为rt,预处理出每个子树中f[v][0/1]表示组合出.没组合出一对值v的链数(从当前儿子出发的链),能组合出一对v值就是可以有一个休息点 然后对于rt,经过rt且合法的路 ...
- BZOJ 3697: 采药人的路径 点分治
好久不做点分治的题了,正好在联赛之前抓紧复习一下. 先把边权为 $0$ 的置为 $-1$.定义几个状态:$f[dis][0/1],g[dis][0/1]$ 其中 $f$ 代表在当前遍历的子树内的答案. ...
- 【BZOJ】3697: 采药人的路径
3697: 采药人的路径 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1718 Solved: 602[Submit][Status][Discu ...
- 【BZOJ】【3697】采药人的路径&【3127】【USACO2013 Open】Yin and Yang
点分治 Orz hzwer 倒是比较好想到点分治……然而在方案统计这里,我犯了两个错误…… 1.我比较傻逼的想的是:通过儿子来更新父亲,也就是统计以x为根的子树中xxxx的路径有多少条……这样转移. ...
- bzoj千题计划248:bzoj3697: 采药人的路径
http://www.lydsy.com/JudgeOnline/problem.php?id=3697 点分治 路径0改为路径-1 g[i][0/1] 和 f[i][0/1]分别表示当前子树 和 已 ...
- 【BZOJ-3697&3127】采药人的路径&YinandYang 点分治 + 乱搞
3697: 采药人的路径 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 681 Solved: 246[Submit][Status][Discus ...
- BZOJ3697: 采药人的路径
传送门 不是那么裸的点分治. $f[i][0/1]$表示当前节点的一个子树中总权值和为$i$,且是否存在一个前缀使得其前缀和为$i$ $g[i][0/1]$表示当前节点的已遍历过的子树,其余一样. 对 ...
- BZOJ_3697_采药人的路径_点分治
BZOJ_3697_采药人的路径_点分治 Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性 ...
随机推荐
- 洛谷—— P3395 路障
https://www.luogu.org/problem/show?pid=3395 题目背景 此题约为NOIP提高组Day1T1难度. 题目描述 B君站在一个n*n的棋盘上.最开始,B君站在(1, ...
- ansible、zabbix、tcpdump
Ansible 源码安装 https://blog.csdn.net/williamfan21c/article/details/53439307 Ansible安装过程中常遇到的错误 http:// ...
- 【Todo】UDP P2P打洞原理
参考以下两篇文章: https://my.oschina.net/ososchina/blog/369206 http://m.blog.csdn.net/article/details?id=666 ...
- Java笔试面试题007
Java笔试面试题007 1.请用正則表達式匹配出QQ号(如果QQ号码为5-10位). 解答: ^ \d{5,10}$ 2.String, StringBuffer StringBuilder的差别. ...
- 《大话操作系统——做坚实的project实践派》(7)
写操作系统内核须要了解一个详细计算平台的CPU,包含这个CPU里的寄存器和异常中断处理机制
- Spring Boot 使用Java代码创建Bean并注冊到Spring中
从 Spring3.0 開始,添加了一种新的途经来配置Bean Definition,这就是通过 Java Code 配置 Bean Definition. 与Xml和Annotation两种配置方式 ...
- leetcode题解||Container With Most Water问题
problem: Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate ...
- hdu 2795(单点改动)
题意:有h×w大的公告板.有n条公告要写入,每条公告高度都是1,宽度是wi,每次从最上最左的空位写,假设有空位输出第几行.假设没有足够空位输出-1. 题解:注意h最大1e9.但事实上是看n的大小.由于 ...
- Hadoop+HBase+ZooKeeper分布式集群环境搭建
一.环境说明 集群环境至少需要3个节点(也就是3台服务器设备):1个Master,2个Slave,节点之间局域网连接,可以相互ping通,下面举例说明,配置节点IP分配如下: Hostname IP ...
- CentOS 5.5下搭建部署独立SVN服务器全程详解
SVN服务器有2种运行方式:1.独立服务器 (例如:svn://xxx.com/xxx):2.借助apache (例如:http://svn.xxx.com/xxx):为了不依赖apache,我选 ...