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
解题思路:
点分治要求在寻找到一条链时统计答案与重心在链的哪个位置无关。而显然这道题如果枚举重心为中转站是错误的,因为一条链只被统计一次,而中心位置很可能是错误的,所以我们需要修正这一点,就是统计重心路径上可能出现的中心位置。
换句话说,开四个桶来记录,分别记录当前子树内可能出现的中转站(出现过的距离重复,在差分的意义下说明出现和为0的区间),另外一个就是之前子树的答案,每次更新完合并桶就好了。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long lnt;
const int N=;
struct pnt{
int hd;
int dis;
int wgt;
bool vis;
}p[N];
struct ent{
int twd;
int lst;
int vls;
}e[N<<];
lnt f[N<<][],g[N<<][];
int has[N<<];
int n;
lnt top;
int cnt;
lnt ans;
int lim;
int size;
int root;
int maxsize;
void ade(int f,int t,int v)
{
cnt++;
e[cnt].twd=t;
e[cnt].lst=p[f].hd;
e[cnt].vls=v;
p[f].hd=cnt;
return ;
}
void grc_dfs(int x,int f)
{
p[x].wgt=;
int maxs=-;
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(to==f||p[to].vis)
continue;
grc_dfs(to,x);
p[x].wgt+=p[to].wgt;
if(p[to].wgt>maxs)
maxs=p[to].wgt;
}
if(maxs<size-p[x].wgt)
maxs=size-p[x].wgt;
if(maxs<maxsize)
{
maxsize=maxs;
root=x;
}
return ;
}
void ans_dfs(int x,int fa,int dep)
{
lim=std::max(lim,dep);
if(has[p[x].dis])
f[p[x].dis][]++;
else
f[p[x].dis][]++;
has[p[x].dis]++;
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(to==fa||p[to].vis)
continue;
p[to].dis=p[x].dis+e[i].vls;
ans_dfs(to,x,dep+);
}
has[p[x].dis]--;
return ;
}
void bin_dfs(int x)
{
int maxd=;
p[x].vis=true;
g[n][]=;
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(p[to].vis)
continue;
p[to].dis=n+e[i].vls;
lim=;
ans_dfs(to,to,);
maxd=std::max(maxd,lim);
ans+=f[n][]*(g[n][]-);
for(int j=-lim;j<=lim;j++)
ans+=g[n-j][]*f[n+j][]+g[n-j][]*f[n+j][]+g[n-j][]*f[n+j][];
for(int j=n-lim;j<=n+lim;j++)
{
g[j][]+=f[j][];
g[j][]+=f[j][];
f[j][]=f[j][]=;
}
}
for(int i=n-maxd;i<=n+maxd;i++)
g[i][]=g[i][]=;
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(p[to].vis)
continue;
root=;
size=p[to].wgt;
maxsize=0x3f3f3f3f;
grc_dfs(to,to);
bin_dfs(root);
}
return ;
}
int main()
{
scanf("%d",&n);
for(int i=;i<n;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
c=c*-;
ade(a,b,c);
ade(b,a,c);
}
root=;
size=n;
maxsize=0x3f3f3f3f;
grc_dfs(,);
bin_dfs(root);
printf("%lld\n",ans);
return ;
}
BZOJ3697: 采药人的路径(点分治)的更多相关文章
- BZOJ3697采药人的路径——点分治
题目描述 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动.他选择的路径 ...
- BZOJ3697:采药人的路径(点分治)
Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天都要进行采药 ...
- [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 采药人的路径 【点分治】
题目 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天都要进行采药活动.他选择的路径 ...
- 2019.01.09 bzoj3697: 采药人的路径(点分治)
传送门 点分治好题. 题意:给出一棵树,边分两种,求满足由两条两种边数相等的路径拼成的路径数. 思路: 考虑将边的种类转化成边权−1-1−1和111,这样就只用考虑由两条权值为000的路径拼成的路径数 ...
- BZOJ 3697/3127 采药人的路径 (点分治)
题目大意: 从前有一棵无向树,树上边权均为$0$或$1$,有一个采药人,他认为如果一条路径上边权为$0$和$1$的边数量相等,那么这条路径阴阳平衡.他想寻找一条合法的采药路径,保证阴阳平衡.然后他发现 ...
随机推荐
- EventBus框架原理解析(结合源代码)(上)
上一篇文章http://blog.csdn.net/crazy__chen/article/details/47425779 和大家一起模仿EventBus的实现机制.和大家一起写出了一个简易的Eve ...
- 【转】Android应用底部导航栏(选项卡)实例
现在很多android的应用都采用底部导航栏的功能,这样可以使得用户在使用过程中随意切换不同的页面,现在我采用TabHost组件来自定义一个底部的导航栏的功能. 我们先看下该demo实例的框架图: 其 ...
- 分享一段wap框架样式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- FreeBSD是UNIX系统的重要分支,其命令与Linux大部分通用,少部分是其特有。
FreeBSD是UNIX系统的重要分支,其命令与Linux大部分通用,少部分是其特有. 1: man 在线查询 man ls2: ls 查看目录与档案 ls -la3: ln 建立链接文件 ln -f ...
- 今日SGU 5.22
SGU 296 题意:给你一个最多1000位的数,让你删除k位使得剩下的数最大 收获:贪心 #include<bits/stdc++.h> #define de(x) cout<&l ...
- 通用查询实现方案(可用于DDD)[附源码] -- 简介
原文:通用查询实现方案(可用于DDD)[附源码] -- 简介 [声明] 写作不易,转载请注明出处(http://www.cnblogs.com/wiseant/p/3985353.html). [ ...
- POJ 1006 Biorhythms (数论-中国剩余定理)
Biorhythms Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 111285 Accepted: 34638 Des ...
- 【Android】利用自己定义View的重绘实现拖动移动,获取组件的尺寸
以下利用一个app来说明怎样利用自己定义View的重绘实现拖动移动.获取组件的尺寸. 例如以下图,触摸拖动,或者轻轻点击屏幕都能移动图片.假设碰到文字,则会弹出提示. 这里是利用自己定义View的重绘 ...
- android 获取蓝牙已连接设备
蓝牙如果手动配对并已连接,获取连接的设备: 1.检测连接状态: int a2dp = bluetoothAdapter.getProfileConnectionState(BluetoothProfi ...
- 使程序在Linux下后台运行 (关掉终端继续让程序运行的方法)
你是否遇到过这样的情况:从终端软件登录远程的Linux主机,将一堆很大的文件压缩为一个.tar.gz文件,连续压缩了半个小时还没有完成,这时,突然你断网了,你登录不上远程Linux主机了,那么前面的半 ...