POJ 2114 Boatherds 划分树

标题效果:鉴于一棵树,问有两点之间没有距离是k的。

数据的多组

思维:和IOI2011的Race喜欢。不是这么简单。阅读恶心,我是在主要功能的别人的在线副本。

CODE:

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

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

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

inline void Initialize();
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 last,int len);
void GetDis(int x,int last,int len);

int main()
{
	while(scanf("%d",&points) != EOF && points) {
		Initialize();
		for(int y,z,i = 1;i <= points; ++i) {
			while(scanf("%d",&y) != EOF && y) {
				scanf("%d",&z);
				Add(i,y,z),Add(y,i,z);
			}
		}
		while(scanf("%d",&k) != EOF && k) {
			ans = 0;
			size[1] = points;
			memset(v,false,sizeof(v));
			Work(1);
			if(ans)	puts("AYE");
			else	puts("NAY");
		}
		puts(".");
	}
	return 0;
}

inline void Initialize()
{
	total = 0;
	memset(head,0,sizeof(head));
}

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)
{
	_size = INF,_total = size[x];
	GetRoot(x,0);
	x = root;
	v[x] = true;
	ans += Count(x,0,0);
	for(int i = head[x];i;i = next[i]) {
		if(v[aim[i]])	continue;
		ans -= Count(aim[i],x,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(aim[i] == last || v[aim[i]])	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(max_size < _size)
		_size = max_size,root = x;
}

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

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

版权声明:本文博客原创文章,博客,未经同意,不得转载。

时间: 2024-11-09 09:02:35

POJ 2114 Boatherds 划分树的相关文章

POJ 2114 Boatherds (树上点分治)

题目地址:POJ 2114 点分治水题.只是把距离小于等于k改成了等于k.稍微加一点处理就可以了. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <set> #incl

POJ 2114 Boatherds 树的分治

题目大意:给出一棵树,问有没有两点之间的距离是k的.多组数据 思路:和IOI2011的Race一样,比那个简单.读入太恶心了,我是上网上抄的别人的主函数. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 10010 #define INF 0x3f3f3f3f using namespace std; int poi

POJ 2114 Boatherds

Description Boatherds Inc. is a sailing company operating in the country of Trabantustan and offering boat trips on Trabantian rivers. All the rivers originate somewhere in the mountains and on their way down to the lowlands they gradually join and f

[划分树] POJ 2104 K-th Number

K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 51732   Accepted: 17722 Case Time Limit: 2000MS Description You are working for Macrohard company in data structures department. After failing your previous task about key inse

poj 2104 K-th Number(划分树)

题目链接:http://poj.org/problem?id=2104 题目分析:该问题给定一段区间中的值,再给定一段查询区间[ql, qr],需要给出该查询区间中的值在排序后的第K大的值: 使用划分树即可解决该问题:划分树的建树的复杂度为O(NlogN),查询一个区间的第K大值的复杂度为O(logN): 代码如下: #include <cstdio> #include <iostream> #include <algorithm> using namespace st

poj 2401 划分树 求区间第k大的数

题目:http://poj.org/problem?id=2104 划分树待我好好理解下再写个教程吧,觉得网上的内容一般,,, 模板题: 贴代码: #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define CLR(a) memset(a,0,sizeof(a)) const int MAXN = 1000

POJ 2104 K-th Number(区间第k大数)(平方分割,归并树,划分树)

题目链接: http://poj.org/problem?id=2104 解题思路: 因为查询的个数m很大,朴素的求法无法在规定时间内求解.因此应该选用合理的方式维护数据来做到高效地查询. 如果x是第k个数,那么一定有 (1)在区间中不超过x的数不少于k个 (2)在区间中小于x的数有不到k个 因此,如果可以快速求出区间里不超过x的数的个数,就可以通过对x进行二分搜索来求出第k个数是多少. 接下来,我们来看一下如何计算在某个区间里不超过x个数的个数.如果不进行预处理,那么就只能遍历一遍所有元素.

POJ 2104 区间第K大值(划分树做法)

由于深感自己水平低下,把大部分有效时间放在了刷题上,于是好久没写题解了.今天刚学了下划分树的原理,于是写道简单题练练手. 题目链接:http://poj.org/problem?id=2104 划分树的空间复杂度和时间复杂度均为O(nlogn),对于解决该问题而言,每次查询的复杂度为O(logn),比归并树O((log)^3)节省时间[归并树采用了三次二分]. 但是划分树也有自己的缺点,不支持更新以及适用范围狭窄,总之...是时代的眼泪了= = AC代码: #include <iostream>

POJ 2104 K-th Number(区间第k大数)(平方切割,归并树,划分树)

题目链接: http://poj.org/problem? id=2104 解题思路: 由于查询的个数m非常大.朴素的求法无法在规定时间内求解. 因此应该选用合理的方式维护数据来做到高效地查询. 假设x是第k个数,那么一定有 (1)在区间中不超过x的数不少于k个 (2)在区间中小于x的数有不到k个 因此.假设能够高速求出区间里不超过x的数的个数.就能够通过对x进行二分搜索来求出第k个数是多少. 接下来,我们来看一下怎样计算在某个区间里不超过x个数的个数. 假设不进行预处理,那么就仅仅能遍历一遍全