【bzoj3697】采药人的路径 树的点分治
题目描述
给出一棵 $n$ 个点的树,每条边的边权为1或0。求有多少点对 $(i,j)$ ,使得:$i$ 到 $j$ 的简单路径上存在点 $k$ (异于 $i$ 和 $j$ ),使得 $i$ 到 $k$ 的简单路径上0和1数目相等,$j$ 到 $k$ 的简单路径上0和1数目也相等。
输入
第1行包含一个整数N。
接下来N-1行,每行包含三个整数a_i、b_i和t_i,表示这条路上药材的类型。
输出
输出符合采药人要求的路径数目。
样例输入
7
1 2 0
3 1 1
2 4 0
5 2 0
6 3 1
5 7 1
样例输出
1
题解
树的点分治
求满足条件的路径数目,可以考虑点分治,每次求过根节点的方案数,再递归处理子树。
设 $f[x][0/1]$ 表示 $1$ 的数目比 $0$ 的数目多 $x$ ,且 否/是 有满足条件的 $k$ 节点的点数。
设 $g[x][0/1]$ 表示 $0$ 的数目比 $1$ 的数目多 $x$ ,且 否/是 有满足条件的 $k$ 节点的点数。
然后相应的答案贡献就是 $f[x][0]·g[x][1]+f[x][1]·g[x][0]+f[x][1]·g[x][1]$ 。
注意特殊处理数目相等的情况,以及分治中心作为路径端点的情况。
dfs整棵子树,求出答案,减去两端在同一子树内的答案,递归子树。
时间复杂度 $O(n\log n)$
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
using namespace std;
int head[N] , to[N << 1] , val[N << 1] , next[N << 1] , cnt , vis[N] , si[N] , ms[N] , sum , root , md;
long long f[N][2] , g[N][2] , ans;
inline void add(int x , int y , int z)
{
to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
}
void getroot(int x , int fa)
{
int i;
si[x] = 1 , ms[x] = 0;
for(i = head[x] ; i ; i = next[i])
if(!vis[to[i]] && to[i] != fa)
getroot(to[i] , x) , si[x] += si[to[i]] , ms[x] = max(ms[x] , si[to[i]]);
ms[x] = max(ms[x] , sum - si[x]);
if(ms[x] < ms[root]) root = x;
}
void calc(int x , int fa , int now , int cnt)
{
int i;
if(now == 0)
{
if(cnt >= 2) ans ++ ;
cnt ++ ;
}
for(i = head[x] ; i ; i = next[i])
if(!vis[to[i]] && to[i] != fa)
calc(to[i] , x , now + 2 * val[i] - 1 , cnt);
}
void dfs(int x , int fa , int now , int l , int r)
{
int i;
if(now >= l && now <= r)
{
if(now >= 0) f[now][1] ++ ;
else g[-now][1] ++ ;
}
else
{
if(now >= 0) f[now][0] ++ ;
else g[-now][0] ++ ;
}
l = min(l , now) , r = max(r , now) , md = max(md , max(-l , r));
for(i = head[x] ; i ; i = next[i])
if(!vis[to[i]] && to[i] != fa)
dfs(to[i] , x , now + val[i] * 2 - 1 , l , r);
}
void solve(int x)
{
int i , j;
vis[x] = 1 , md = 0 , calc(x , 0 , 0 , 0);
dfs(x , 0 , 0 , 1 , -1) , ans += f[0][1] * (f[0][1] - 1) / 2 , f[0][0] = f[0][1] = 0;
for(i = 1 ; i <= md ; i ++ ) ans += f[i][0] * g[i][1] + f[i][1] * g[i][0] + f[i][1] * g[i][1] , f[i][0] = f[i][1] = g[i][0] = g[i][1] = 0;
for(i = head[x] ; i ; i = next[i])
{
if(!vis[to[i]])
{
md = 0 , dfs(to[i] , 0 , 2 * val[i] - 1 , 0 , 0) , ans -= f[0][1] * (f[0][1] - 1) / 2 , f[0][0] = f[0][1] = 0;
for(j = 0 ; j <= md ; j ++ ) ans -= f[j][0] * g[j][1] + f[j][1] * g[j][0] + f[j][1] * g[j][1] , f[j][0] = f[j][1] = g[j][0] = g[j][1] = 0;
sum = si[to[i]] , root = 0 , getroot(to[i] , 0) , solve(root);
}
}
}
int main()
{
int n , i , x , y , z;
scanf("%d" , &n);
for(i = 1 ; i < n ; i ++ ) scanf("%d%d%d" , &x , &y , &z) , add(x , y , z) , add(y , x , z);
sum = n , root = 0 , ms[0] = n , getroot(1 , 0) , solve(root);
printf("%lld\n" , ans);
return 0;
}
【bzoj3697】采药人的路径 树的点分治的更多相关文章
- [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 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天都要进行采药 ...
- BZOJ3697 采药人的路径 【点分治】
题目 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天都要进行采药活动.他选择的路径 ...
- BZOJ3697: 采药人的路径(点分治)
Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动 ...
- 2019.01.09 bzoj3697: 采药人的路径(点分治)
传送门 点分治好题. 题意:给出一棵树,边分两种,求满足由两条两种边数相等的路径拼成的路径数. 思路: 考虑将边的种类转化成边权−1-1−1和111,这样就只用考虑由两条权值为000的路径拼成的路径数 ...
- [bzoj3697]采药人的路径——点分治
Brief Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天 ...
- BZOJ3697: 采药人的路径
传送门 不是那么裸的点分治. $f[i][0/1]$表示当前节点的一个子树中总权值和为$i$,且是否存在一个前缀使得其前缀和为$i$ $g[i][0/1]$表示当前节点的已遍历过的子树,其余一样. 对 ...
随机推荐
- 考研编程练习----swap
void swap(int a ,int b) { a^=b; b^=a; //b =b^a^b //b = b^b^a;//b = a; 按位异或满足交换律 a^=b; //a = a^b^a ...
- OO原则汇总
SOLID原则:http://www.cnblogs.com/lanxuezaipiao/archive/2013/06/09/3128665.html https://www.cnblogs.com ...
- [agc006D]Median Pyramid Hard-[二分+乱搞]
Description 题目大意:给你一个长度为n*2-1的排列,将除了该序列头尾的两个数外的其他数(设为i)变为原序列i-1,i,i+1下标数的中位数.求最后的数是什么.例子如下: Solution ...
- [Bootstrap 源码解析]——bootstrap源码之初始化
bootstrap源码之初始化 我们先来分析normalize.less编译后的源码,我们知道normalize.css是一个专门将不同浏览器的默认css特性设置为统一效果的css库,它和reset. ...
- Struts 2(一):初识Struts
[很久以前的笔记,后续继续完善] 在了解Struts 2框架之前,首先了解一下Model 1和Model 2架构,以及它们的优缺点. 1.1 Model 1架构模式 Model 1的核心是JSP文件, ...
- 逆向某停车app(原创)
最近一直在做python开发的事情,信息安全方面做得很少,也是"蛋蛋"的忧伤呀.今天有朋友请我帮忙,将一个app里的文字和图标替换一下,花了一下午和一晚上的时间搞了一下,主要是图标 ...
- 视觉SLAM中的深度估计问题
一.研究背景 视觉SLAM需要获取世界坐标系中点的深度. 世界坐标系到像素坐标系的转换为(深度即Z): 深度的获取一共分两种方式: a)主动式 RGB-D相机按照原理又分为结构光测距.ToF相机 To ...
- 人脸检测及识别python实现系列(1)——配置、获取实时视频流
人脸检测及识别python实现系列(1)——配置.获取实时视频流 1. 前言 今天用多半天的时间把QQ空间里的几篇年前的旧文搬到了这里,算是完成了博客搬家.QQ空间里还剩下一些记录自己数学学习路线的学 ...
- Python数据可视化的10种技能
今天我来给你讲讲Python的可视化技术. 如果你想要用Python进行数据分析,就需要在项目初期开始进行探索性的数据分析,这样方便你对数据有一定的了解.其中最直观的就是采用数据可视化技术,这样,数据 ...
- 模拟IDE上的run过程
看了一下老陈写的模仿JDK动态代理,从中取一部分单独扩展,模拟一下IDE上的run过程(不愧是老陈,去年写的东西我要现在才能理解) 对run过程的猜想 在点击run的过程中应该做了不少事.先编译运行r ...