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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章