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

【BZOJ3697】采药人的路径

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。

题解:可能我以前学的是假的点分治~

注意一点:起点和终点相同,休息点不同的路径,算作相同的路径。

当我们以x为分治中心时,我们遍历x的所有子树,并令f[i][0/1]表示在之前扫过的子树中,到x的路径上的阳-阴=i,不存在(存在)一个休息点的点数,g[i][0/1]表示在当前的子树中,到x的路径上的阳-阴=i,不存在(存在)一个休息站的点数。那么用f和g来更新答案就行了。别忘了算上起点为x的情况。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn=100010;
typedef long long ll;
int n,cnt,root,mx,maxx,tot,d;
ll ans;
int to[maxn<<1],next[maxn<<1],val[maxn<<1],head[maxn],dep[maxn],siz[maxn],vis[maxn],s[maxn];
int f[maxn<<1][2],g[maxn<<1][2];
int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
void getr(int x,int fa)
{
	siz[x]=1;
	int mx=0;
	for(int i=head[x];i!=-1;i=next[i])
	{
		if(vis[to[i]]||to[i]==fa)	continue;
		getr(to[i],x),siz[x]+=siz[to[i]],mx=max(mx,siz[to[i]]);
	}
	if(max(tot-siz[x],mx)<maxx)	root=x,maxx=max(tot-siz[x],mx);
}
void getd(int x,int fa)
{
	d=max(d,max(dep[x],-dep[x]));
	if(s[dep[x]+maxn])	g[dep[x]+maxn][1]++;
	else	g[dep[x]+maxn][0]++;
	s[dep[x]+maxn]++;
	for(int i=head[x];i!=-1;i=next[i])
	{
		if(vis[to[i]]||to[i]==fa)	continue;
		dep[to[i]]=dep[x]+val[i],getd(to[i],x);
	}
	s[dep[x]+maxn]--;
}
void dfs(int x)
{
	vis[x]=1;
	int i,j,dd=0;
	for(i=head[x];i!=-1;i=next[i])
	{
		if(vis[to[i]])	continue;
		dep[to[i]]=val[i],d=0,getd(to[i],x),dd=max(dd,d);
		for(j=maxn-d;j<=maxn+d;j++)	ans+=(ll)f[2*maxn-j][0]*g[j][1]+f[2*maxn-j][1]*g[j][0]+f[2*maxn-j][1]*g[j][1];
		ans+=(ll)f[maxn][0]*g[maxn][0]+g[maxn][1];
		for(j=maxn-d;j<=maxn+d;j++)	f[j][0]+=g[j][0],f[j][1]+=g[j][1],g[j][0]=g[j][1]=0;
	}
	for(i=maxn-dd;i<=maxn+dd;i++)	f[i][0]=f[i][1]=0;
	for(i=head[x];i!=-1;i=next[i])
	{
		if(vis[to[i]])	continue;
		maxx=1<<30,tot=siz[to[i]],getr(to[i],x),dfs(root);
	}
}
void add(int a,int b,int c)
{
	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
int main()
{
	n=rd();
	int i,a,b,c;
	memset(head,-1,sizeof(head));
	for(i=1;i<n;i++)	a=rd(),b=rd(),c=rd()*2-1,add(a,b,c),add(b,a,c);
	maxx=1<<30,tot=n,getr(1,0),dfs(root);
	printf("%lld",ans);
	return 0;
}
时间: 2024-11-06 14:00:25

【BZOJ3697】采药人的路径 点分治的相关文章

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

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

BZOJ3697 采药人的路径

点分治...尼玛啊!蒟蒻怎么做的那么桑心%>_<% Orz hzwer 蒟蒻就补充一下hzwer没讲的东西: (1)对于阴性的植物权值设为-1,阳性的设为+1 (2)最后一段就是讲如何利用新的子树的f[]值求出ans和更新g[] 1 /************************************************************** 2 Problem: 3697 3 User: rausen 4 Language: C++ 5 Result: Accepted 6

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

3697: 采药人的路径 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 681  Solved: 246[Submit][Status][Discuss] Description 采药人的药田是一个树状结构,每条路径上都种植着同种药材.采药人以自己对药材独到的见解,对每种药材进行了分类.大致分为两类,一种是阴性的,一种是阳性的.采药人每天都要进行采药活动.他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径.

【BZOJ】【3697】采药人的路径 &amp; 【3127】【USACO2013 Open】Yin and Yang

点分治 Orz hzwer 倒是比较好想到点分治……然而在方案统计这里,我犯了两个错误…… 1.我比较傻逼的想的是:通过儿子来更新父亲,也就是统计以x为根的子树中xxxx的路径有多少条……这样转移. 然而这实在是太傻逼了,黄学长教做人:从父亲来更新儿子,走到一个节点直接更新路径的统计数,反正我们要的是[经过root的xx路径的数量] 所以可以一遍dfs直接搞出来…… 2.统计方案的方式也想错了……我只考虑了以root作为中转站的路径,然而经过root的路径中,并不只有这种路径是合法的……中转站在

P4930「FJ2014集训」采药人的路径

题目:P4930「FJ2014集训」采药人的路径 思路: 这篇不算题解,是让自己复习的,什么都没说清楚. 很久没有写点分治了,以前为了赶课件学的太急,板子都没打对就照着题解写题,导致学得很不扎实. 这道题差不多是在郭老师的指导下一点点凑出来的,还是没能自己完整写出一道题,惭愧. 这道题大意是:给出一棵边权为0/1的树,求满足以下条件的路径总数:0的个数等于1的个数,且路径上存在一点到路径两端也满足该条件. 这种求路径总数的题,可以想到用点分治. 把0看作-1,就可以转化为路径边权和为0. 如果没

【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,表示这条路上药材的类型. 输出 输出符合采药人要求的路径数目. 样例输入 71 2 03 1 12 4 05 2 06 3 15 7

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

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

【BZOJ3784】树上的路径 点分治序+ST表

[BZOJ3784]树上的路径 Description 给定一个N个结点的树,结点用正整数1..N编号.每条边有一个正整数权值.用d(a,b)表示从结点a到结点b路边上经过边的权值.其中要求a<b.将这n*(n-1)/2个距离从大到小排序,输出前M个距离值. Input 第一行两个正整数N,M 下面N-1行,每行三个正整数a,b,c(a,b<=N,C<=10000).表示结点a到结点b有一条权值为c的边. Output 共M行,如题所述. Sample Input 5 10 1 2 1

【BZOJ-3784】树上的路径 点分治 + ST + 堆

3784: 树上的路径 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 462  Solved: 153[Submit][Status][Discuss] Description 给定一个N个结点的树,结点用正整数1..N编号.每条边有一个正整数权值.用d(a,b)表示从结点a到结点b路边上经过边的权值.其中要求a<b.将这n*(n-1)/2个距离从大到小排序,输出前M个距离值. Input 第一行两个正整数N,M 下面N-1行,每行三个正整数a,