jzoj3234. 阴阳

题目描述

Description
Farmer John 正在在计划自己的农场漫步。他的农场的结构就像一棵树:农场有N个谷仓(1<= N <=100,000),分别由N-1条路链接。这样,他便可以通过这些谷仓间的道路遍及各个谷仓。Farmer John想要选择一条路线:这条路线的起点和终点分别为农场中两个不同的谷仓,这条路线不能重复经过一条边两次。Farmer John担心这条路径可能会偏长,所以他想在路线上寻找一个休息点(当然这个休息点不能为起点或者终点)。

每条边的两旁都是牛群,要么是Charcolais(白毛),要么是Angus(黑毛)。Farmer John是一个聪明人,所以他想要在他通过小路的同时平衡小路两侧阴阳的力量。他要选择一条路径使得他从起点到休息站,和从休息站到终点这两段路上都满足路两边的Charcolais牛群和Angus牛群总数量相同。

Farmer John好奇他能找到多少条如上所述的平衡的路径。我们认为,当且仅当两条路线的边的集合不同时,这两条路径才被认为是不同的,否则认为是相同的路线。就算路线上有多个有效的“休息站”的位置能使路线平衡,我们也只记为一条路线。

请帮助计算有多少条不同的平衡路线。

Input
第1行:包含一个整数N。

第2… N行:每行包含三个整数a_i、b_i和t_i,表示第i条路径连接的两个谷仓a_i、b_i。t_i表示第i条路边上的牛群种类:0表示Charcolais,1表示Angus。

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

Data Constraint
1<= N <=100,000

Hint
不存在长度为2的路线,所以我们只能考虑长度为4的路线,路线3-1-2-5-7休息点设在2是一条平衡路线。

题解

点分治裸题(相对)
设白为-1,黑为1,则要找一条路径使得存在某个点,使得分成的两段的路径和都为0
点分治,先称每个点为普通点,若一个普通点到分治点的路径上存在一段前缀和为0,则称其为关键点(同时也是普通点)
可能与题解说法不同因为我没有看题解
通过维护每个点到分治点上路径的权值和情况可以判断一个点是否是关键点(如果当前的和在之前某个位置就出现了,那么中间的路径的和为0)
初始存在一个和为0的点(起点)
对于一条合法路径(u–分治点–v),u和v中至少有一个为关键点,且sum[u]+sum[v]=0,再加上u/v–分治点的合法情况(当且仅当该点的和为0,而且之前和为0的点至少存在2个
注意减去u和v都是关键点的情况

code

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define inf 2133333333
using namespace std;

int a[200001][3];
int ls[100001];
int size[100001];
int bz[100001];
int b[200001]; //special
int B[200001]; //normal
int c[200001];
int b2[100001];
int B2[100001];
int n,i,j,k,l,len,min1,min2,l1,l2;
long long ans;

void New(int x,int y,int z)
{
    
    
	++len;
	a[len][0]=y;
	a[len][1]=ls[x];
	ls[x]=len;
	a[len][2]=z;
}

void dfs2(int Fa,int t)
{
    
    
	int i;
	
	size[t]=1;
	
	for (i=ls[t]; i; i=a[i][1])
	if (a[i][0]!=Fa && !bz[a[i][0]])
	{
    
    
		dfs2(t,a[i][0]);
		size[t]+=size[a[i][0]];
	}
}

void dfs3(int Fa,int t,int Size)
{
    
    
	int i,sum=0,mx=Size;
	
	for (i=ls[t]; i; i=a[i][1])
	if (a[i][0]!=Fa && !bz[a[i][0]])
	{
    
    
		sum+=size[a[i][0]];
		mx=max(mx,size[a[i][0]]);
	}
	
	if (mx<min1)
	{
    
    
		min1=mx;
		min2=t;
	}
	
	for (i=ls[t]; i; i=a[i][1])
	if (a[i][0]!=Fa && !bz[a[i][0]])
	dfs3(t,a[i][0],Size+sum-size[a[i][0]]+1);
}

void dfs4(int Fa,int t,int s)
{
    
    
	int i;
	
	ans+=b[-s+100000];
	if (c[s+100000])
	{
    
    
		ans+=B[-s+100000]-b[-s+100000];
		
		if (!s && c[s+100000]>1)
		++ans;
	}
	
//	---
	
	++c[s+100000];
	
	for (i=ls[t]; i; i=a[i][1])
	if (a[i][0]!=Fa && !bz[a[i][0]])
	dfs4(t,a[i][0],s+a[i][2]);
	
	--c[s+100000];
}

void dfs5(int Fa,int t,int s)
{
    
    
	int i;
	
	++B[s+100000];
	if (B[s+100000]==1)
	B2[++l2]=s+100000;
	
	if (c[s+100000])
	{
    
    
		++b[s+100000];
		
		if (b[s+100000]==1)
		b2[++l1]=s+100000;
	}
	
//	---
	
	++c[s+100000];
	
	for (i=ls[t]; i; i=a[i][1])
	if (a[i][0]!=Fa && !bz[a[i][0]])
	dfs5(t,a[i][0],s+a[i][2]);
	
	--c[s+100000];
}

void dfs1(int t)
{
    
    
	int i;
	
	dfs2(0,t);
	min1=inf;
	dfs3(0,t,0);
	
	t=min2;
	bz[t]=1;
	
	l1=0;
	l2=0;
	
	for (i=ls[t]; i; i=a[i][1])
	if (!bz[a[i][0]])
	{
    
    
		++c[0+100000];
		
		dfs4(t,a[i][0],a[i][2]);
		dfs5(t,a[i][0],a[i][2]);
		
		--c[0+100000];
	}
	
	fo(i,1,l1) b[b2[i]]=0;
	fo(i,1,l2) B[B2[i]]=0;
	
	for (i=ls[t]; i; i=a[i][1])
	if (!bz[a[i][0]])
	dfs1(a[i][0]);
}

int main()
{
    
    
	scanf("%d",&n);
	fo(i,2,n)
	{
    
    
		scanf("%d%d%d",&j,&k,&l);
		l=l*2-1;
		
		New(j,k,l);
		New(k,j,l);
	}
	
	dfs1(1);
	
	printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/gmh77/article/details/100003237