天天看点

POJ 1987 BZOJ 3365 Distance Statistics 树的分治(点分治)

题目大意:(同poj1741,刷一赠一系列)

CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 40010
#define INF 0x3f3f3f3f
using namespace std;

int points,edges,k;
int head[MAX],total;
int next[MAX << 1],length[MAX << 1],aim[MAX << 1];

bool v[MAX];
int cnt[MAX];
int _size,size[MAX],root,_total;
int dis[MAX],p;

char s[10];

inline void Add(int x,int y,int len);

void Work(int x);
void GetRoot(int x,int last);
inline int Count(int x,int len);
void GetDis(int x,int last,int len);

int main()
{
	cin >> points >> edges;
	for(int x,y,z,i = 1;i <= edges; ++i) {
		scanf("%d%d%d%s",&x,&y,&z,s);
		Add(x,y,z),Add(y,x,z);
	}
	cin >> k;
	Work(1);
	int ans = 0;
	for(int i = 1;i <= points; ++i)
		ans += cnt[i];
	cout << ans << endl;
	return 0;
}

inline void Add(int x,int y,int len)
{
	next[++total] = head[x];
	aim[total] = y;
	length[total] = len;
	head[x] = total;
}

void Work(int x)
{
	_total = size[x] ? size[x]:points;
	_size = INF;
	GetRoot(x,0);
	x = root;
	v[x] = true;
	cnt[x] = Count(x,0);
	for(int i = head[x];i;i = next[i]) {
		if(v[aim[i]])	continue;
		cnt[x] -= Count(aim[i],length[i]);
		Work(aim[i]);
	}
}

void GetRoot(int x,int last)
{
	size[x] = 1;
	int max_size = 0;
	for(int i = head[x];i;i = next[i]) {
		if(v[aim[i]] || aim[i] == last)	continue;
		GetRoot(aim[i],x);
		size[x] += size[aim[i]];
		max_size = max(max_size,size[aim[i]]);
	} 
	max_size = max(max_size,_total - size[x]);
	if(_size > max_size)
		_size = max_size,root = x;
}

inline int Count(int x,int len)
{
	p = 0;
	GetDis(x,0,len);
	sort(dis + 1,dis + p + 1);
	int l = 1,r = p,re = 0;
	while(l < r) {
		if(dis[l] + dis[r] <= k)
			re += (r - l),++l;
		else	--r;
	}
	return re;
}

void GetDis(int x,int last,int len)
{
	dis[++p] = len;
	for(int i = head[x];i;i = next[i]) {
		if(v[aim[i]] || aim[i] == last)	continue;
		GetDis(aim[i],x,len + length[i]);
	}
}