BZOJ_3697_采药人的路径_点分治

Description

采药人的药田是一个树状结构,每条路径上都种植着同种药材。
采药人以自己对药材独到的见解,对每种药材进行了分类。大致分为两类,一种是阴性的,一种是阳性的。
采药人每天都要进行采药活动。他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径。采药工作是很辛苦的,所以他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的。他想知道他一共可以选择多少种不同的路径。

Input

第1行包含一个整数N。
接下来N-1行,每行包含三个整数a_i、b_i和t_i,表示这条路上药材的类型。

Output

输出符合采药人要求的路径数目。

Sample Input

7
1 2 0
3 1 1
2 4 0
5 2 0
6 3 1
5 7 1

Sample Output

1

HINT

对于100%的数据,N ≤ 100,000。


路径计数问题,很容易想到点分治。把0当成-1,那么路径长度为0的路径就是阴阳平衡的。

设f[i][0/1]表示到根的路径长度为i,且路径上没有/有阴阳平衡的路径的路径条数。

设g[i][0/1]表示到根的路径长度为-i,且路径上没有/有阴阳平衡的路径的路径条数。

对答案的贡献为f[i][0]*g[i][1]+f[i][1]*g[i][0]+f[i][1]*g[i][1]

然后发现向下找路径的时候长度一定是一个范围(因为边权为1或-1),我们记录这个范围就能求出这条路径上还有没有平衡的了。

其他细节比较多

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 200050
typedef long long ll;
int head[N],to[N<<1],nxt[N<<1],val[N<<1],cnt;
int n,fag[N],siz[N],tot,root,maxdeep;
bool used[N];
ll ans,f[N][2],g[N][2];
inline void add(int u,int v,int w) {
to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
}
void getroot(int x,int y) {
fag[x]=0; siz[x]=1;
int i;
for(i=head[x];i;i=nxt[i]) {
if(to[i]!=y&&!used[to[i]]) {
getroot(to[i],x);
siz[x]+=siz[to[i]];
fag[x]=max(fag[x],siz[to[i]]);
}
}
fag[x]=max(fag[x],tot-siz[x]);
if(fag[root]>fag[x]) root=x;
}
void calc(int x,int y,int now,int cnt) {
int i;
if(now==0) {
if(cnt>=2) ans++;
cnt++;
}
for(i=head[x];i;i=nxt[i]) {
if(to[i]!=y&&!used[to[i]]) {
calc(to[i],x,now+val[i],cnt);
}
}
}
void getdep(int x,int y,int now,int l,int r) {
siz[x]=1;
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); maxdeep=max(maxdeep,max(-l,r));
for(i=head[x];i;i=nxt[i]) {
if(to[i]!=y&&!used[to[i]]) {
getdep(to[i],x,now+val[i],l,r);
siz[x]+=siz[to[i]];
}
}
}
void work(int x) {
int i,j;
used[x]=1; maxdeep=0; calc(x,0,0,0);
getdep(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<=maxdeep;i++) ans+=f[i][1]*g[i][1]+f[i][0]*g[i][1]+f[i][1]*g[i][0],f[i][0]=f[i][1]=g[i][0]=g[i][1]=0;
for(i=head[x];i;i=nxt[i]) {
if(!used[to[i]]) {
maxdeep=0; getdep(to[i],0,val[i],0,0); ans-=f[0][1]*(f[0][1]-1)/2; f[0][0]=f[0][1]=0;
for(j=1;j<=maxdeep;j++) ans-=f[j][1]*g[j][1]+f[j][0]*g[j][1]+f[j][1]*g[j][0],f[j][0]=f[j][1]=g[j][0]=g[j][1]=0;
tot=siz[to[i]];
root=0;
getroot(to[i],0);
work(root);
}
}
}
int main() {
scanf("%d",&n);
int i,x,y,z;
for(i=1;i<n;i++) {
scanf("%d%d%d",&x,&y,&z);
if(!z) z--;
add(x,y,z); add(y,x,z);
}
tot=n;
fag[0]=1<<30;
getroot(1,0);
work(root);
printf("%lld\n",ans);
}

BZOJ_3697_采药人的路径_点分治的更多相关文章

  1. [bzoj3697]采药人的路径_点分治

    采药人的路径 bzoj-3697 题目大意:给你一个n个节点的树,每条边分为阴性和阳性,求满足条件的链的个数,使得这条链上阴性的边的条数等于阳性的边的条数,且这条链上存在一个节点,这个节点到一个端点的 ...

  2. 【BZOJ-3697&3127】采药人的路径&YinandYang 点分治 + 乱搞

    3697: 采药人的路径 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 681  Solved: 246[Submit][Status][Discus ...

  3. BZOJ3697 采药人的路径 【点分治】

    题目 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天都要进行采药活动.他选择的路径 ...

  4. 【BZOJ3697】采药人的路径(点分治)

    题意:采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动.他选择的路径是很 ...

  5. BZOJ3697: 采药人的路径(点分治)

    Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动 ...

  6. 2019.01.09 bzoj3697: 采药人的路径(点分治)

    传送门 点分治好题. 题意:给出一棵树,边分两种,求满足由两条两种边数相等的路径拼成的路径数. 思路: 考虑将边的种类转化成边权−1-1−1和111,这样就只用考虑由两条权值为000的路径拼成的路径数 ...

  7. bzoj 3697: 采药人的路径【点分治】

    点分治,设当前处理的块的重心为rt,预处理出每个子树中f[v][0/1]表示组合出.没组合出一对值v的链数(从当前儿子出发的链),能组合出一对v值就是可以有一个休息点 然后对于rt,经过rt且合法的路 ...

  8. 【BZOJ3697】采药人的路径 点分治

    [BZOJ3697]采药人的路径 Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是 ...

  9. BZOJ_1316_树上的询问_点分治

    BZOJ_1316_树上的询问_点分治 Description 一棵n个点的带权有根树,有p个询问,每次询问树中是否存在一条长度为Len的路径,如果是,输出Yes否输出No. Input 第一行两个整 ...

随机推荐

  1. java中Scanner类nextLine()和next()的区别和使用方法

    转载:http://blog.csdn.net/zhiyuan_ma/article/details/51592730 在实现字符窗口的输入时,很多人更喜欢选择使用扫描器Scanner,它操作起来比较 ...

  2. Day9 进程理论 开启进程的两种方式 多进程实现并发套接字 join方法 Process对象的其他属性或者方法 守护进程 操作系统介绍

    操作系统简介(转自林海峰老师博客介绍) #一 操作系统的作用: 1:隐藏丑陋复杂的硬件接口,提供良好的抽象接口 2:管理.调度进程,并且将多个进程对硬件的竞争变得有序 #二 多道技术: 1.产生背景: ...

  3. Python爬虫 - 爬取百度html代码前200行

    Python爬虫 - 爬取百度html代码前200行 - 改进版,  增加了对字符串的.strip()处理 源代码如下: # 改进版, 增加了 .strip()方法的使用 # coding=utf-8 ...

  4. django1.8升级1.9的几个问题

    1.URL Pattern警告,旧式的URL定义方法将在1.10版本中被废止,所以这个版本仅仅是警告,不过这个警告让我看到了升级1.9这个非LTS版本的意义. 2.Django自身所带Models变化 ...

  5. Java并发编程——BlockingQueue

    简介 BlockingQueue很好的解决了多线程中,如何高效安全"传输"数据的问题.通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便利. 阻塞队列是 ...

  6. 这就是我想要的 VSCode 插件!

    简评:VSCode 是一个开源的跨平台编辑器,是我最满意的 IDE 之一.本文介绍了几种使用的插件,确实解决了很多的痛点. Quokka.js Quokka.js 会在您键入代码编辑器中显示各种执行结 ...

  7. JavaScript匿名自执行函数~function(){}

    原博客:https://blog.csdn.net/yaojxing/article/details/72784774 1.匿名函数的常见场景 js中的匿名函数是一种很常见的函数类型,比较常见的场景: ...

  8. javascript 易漏点

    javascript 是一种解释型语言,不是java或c++那样的编译语言.javascript指令以普通文本形式传递给浏览器,然后依次解释执行.它们不必首先“编译”成只有计算机处理器能理解的机器码. ...

  9. django+appium实现UI自动化测试平台---构思版

             背景 UI自动化,在进行的过程中,难免会遇到平台化, 在实际的工作中,有的领导也会想要实现自动化测试的平台化.自动化平台化后,有了更为实际的成果, 在做UI自动化,很想吧现在的自动化 ...

  10. 在C++98基础上学习C++11新特性

    自己一直用的是C++98规范来编程,对于C++11只闻其名却没用过其特性.近期因为工作的需要,需要掌握C++11的一些特性,所以查阅了一些C++11资料.因为自己有C++98的基础,所以从C++98过 ...