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$的边数量相等,那么这条路径阴阳平衡.他想寻找一条合法的采药路径,保证阴阳平衡.然后他发现 ...
随机推荐
- Ural 1303 Minimal Coverage(贪心)
题目地址:Ural 1303 先按每一个线段的左端点排序,然后设置一个起点s.每次都从起点小于等于s的线段中找到一个右端点最大的. 并将该右端点作为新的起点s,然后继续找. 从左到右扫描一遍就可以. ...
- 使用Java8提供的Duration类制作字幕时间轴调整工具
网上下载的字幕有时和片源的时间轴不一致.我们能够自己写一个工具来调整,也就是总体向前移动几秒,或者向后移动几秒.Java8中提供的Duration类使得这样的时间计算极其方便.以下就以最简单的srt字 ...
- Redis封装之Hash
RedisHashService: /// <summary> /// Hash:类似dictionary,通过索引快速定位到指定元素的,耗时均等,跟string的区别在于不用反序列化,直 ...
- 【基础篇】DatePickerDialog日期控件的基本使用(二) ——分别获取年、月、日、时、分
项目步骤: 1.在Main.xml布局文件中定义对应的组件,Main.xml内容如下: <?xml version="1.0" encoding="utf-8&qu ...
- codeforces 710A King Moves(水)
output standard output The only king stands on the standard chess board. You are given his position ...
- sqlserver自定义函数(标量值函数,表值函数)
用户自定义的函数有两类:表值函数.标量值函数. 表值函数:返回值是数据表的函数 调用方式 select b.* from tableA a accross apply Fun_BiaoZhiFun ...
- VirtualBox内刚刚安装完Debian9系统,也无法设置共享文件夹。解决的方法就是安装VirtualBox客户端增强包。
VirtualBox内刚刚安装完Debian9系统,也无法设置共享文件夹.解决的方法就是安装VirtualBox客户端增强包. 1.若直接安装客户端增强包会得到如下提示:root@debian:/op ...
- 安装成功的nginx,如何添加未编译安装模块(非覆盖安装http_image_filter_module)
背景:1.做了图片上传小项目.2.图片上传,需要多图管理.3.图片上传,需要存储到Fastdfs.4.Fastdfs上的图片,和Nginx结合.5.Nginx从Fastdfs获得的图片,需要使用缩略图 ...
- 剑指offer_面试题6_重建二叉树(分解步骤,逐个击破)
题目:输入某二叉树的前序遍历和中序遍历的结果.请重建出该二叉树.如果输入的前序遍历和中序遍历的结果中都不含反复的数字. 比如:输入前序遍历 {1,2,4,7,3,5,6,8} 和中序遍历序列 {4,7 ...
- Linux中去除windows文件中的控制字符
Windows下的文本文件拿到Linux下时,会在文本行最后面出现很多字符:^M Linux下去除掉的方法是:dos2unix file(需要软件包dos2unix) 当然逆转的方法为unix2dos ...