BZOJ_3697_采药人的路径_点分治
BZOJ_3697_采药人的路径_点分治
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
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_采药人的路径_点分治的更多相关文章
- [bzoj3697]采药人的路径_点分治
采药人的路径 bzoj-3697 题目大意:给你一个n个节点的树,每条边分为阴性和阳性,求满足条件的链的个数,使得这条链上阴性的边的条数等于阳性的边的条数,且这条链上存在一个节点,这个节点到一个端点的 ...
- 【BZOJ-3697&3127】采药人的路径&YinandYang 点分治 + 乱搞
3697: 采药人的路径 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 681 Solved: 246[Submit][Status][Discus ...
- BZOJ3697 采药人的路径 【点分治】
题目 采药人的药田是一个树状结构,每条路径上都种植着同种药材. 采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的. 采药人每天都要进行采药活动.他选择的路径 ...
- 【BZOJ3697】采药人的路径(点分治)
题意:采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动.他选择的路径是很 ...
- BZOJ3697: 采药人的路径(点分治)
Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动 ...
- 2019.01.09 bzoj3697: 采药人的路径(点分治)
传送门 点分治好题. 题意:给出一棵树,边分两种,求满足由两条两种边数相等的路径拼成的路径数. 思路: 考虑将边的种类转化成边权−1-1−1和111,这样就只用考虑由两条权值为000的路径拼成的路径数 ...
- bzoj 3697: 采药人的路径【点分治】
点分治,设当前处理的块的重心为rt,预处理出每个子树中f[v][0/1]表示组合出.没组合出一对值v的链数(从当前儿子出发的链),能组合出一对v值就是可以有一个休息点 然后对于rt,经过rt且合法的路 ...
- 【BZOJ3697】采药人的路径 点分治
[BZOJ3697]采药人的路径 Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是 ...
- BZOJ_1316_树上的询问_点分治
BZOJ_1316_树上的询问_点分治 Description 一棵n个点的带权有根树,有p个询问,每次询问树中是否存在一条长度为Len的路径,如果是,输出Yes否输出No. Input 第一行两个整 ...
随机推荐
- Spring中对象和属性的注入方式
一:Spring的bean管理 1.xml方式 bean实例化三种xml方式实现 第一种 使用类的无参数构造创建,首先类中得有无参构造器(重点) 第二种 使用静态工厂创建 (1)创建静态的方法,返回类 ...
- Spring ioc 详解
引述:IoC(控制反转:Inverse of Control)是Spring容器的内核,AOP.声明式事务等功能在此基础上开花结果.但是IoC这个重要的概念却比较晦涩隐讳,不容易让人望文生义,这不能不 ...
- sqlplus 登录数据库
sqlplus pams/pamscncc@ORCLMIS
- J2EE架构师之路
不经意的回首,工作进入第五个年头了,发现走过了从Java程序员到J2EE架构师的历程. 发现电脑上安装了各种各样的J2EE工具:JBuilder, WSAD, Eclipse, Rose, Toget ...
- python---内置模块
时间模块 时间分为三种类型:时间戳,结构化时间,格式化时间 #时间模块,time import time #时间戳 x = time.time() time.gmtime() #将时间戳转换成UTC时 ...
- Aptana版本回滚的方法
最近Aptana对Django1.7的编译支持有点问题,开发环境必须使用Django1.6版本,今天看了一眼它的官网,版本已经到3.6.1,我的版本还是3.4.2,就checkupdate升级到3.6 ...
- Flask入门之SQLAlchemy配置与数据库连接
1. 安装SQLAlchemy pip install flask-sqlalchemy 2. 导入和配置 from flask_sqlalchemy import SQLAlchemy basedi ...
- 一个完整的html 每个标签的含义
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Ubuntu 16.04 安装 Docker
在Ubuntu上安装Docker, 非常简单, 我测试过 16.04, 17.04, 以及最新版 18.04,都是可以成功安装,并使用的. 第一步: 启动root账号 第二步: 配置网络,能上网 ...
- java的系统时间,怎么计算从现在到凌晨还剩下多少时间?
Apache commons-lang3 long milliSecondsLeftToday = 86400000 - DateUtils.getFragmentInMilliseconds(Cal ...