POJ-2114 Boatherds (树分治)

3 篇文章 0 订阅
2 篇文章 0 订阅

Boatherds

Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 3775 Accepted: 1233

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 finally the single resulting river flows to the sea. Moreover, the Trabantian villages are exactly at the rivers' springs, junctions and at the mouth of the largest river. Please note that more than 2 rivers can join at a junction. However, the rivers always form a tree (with villages as vertices).

The pricing policy of the Boatherds is very simple: each segment of each river between two villages is assigned a price (the price is same in both directions), so if a tourist requests a journey between any two villages, the ticket office clerks just add the prices of the segments along the only path between the villages.

One day, a very strange tourist appeared. She told the clerks that she returns to her country on the next day and she wants to spend all the remaining money on a boat trip, so they should find a route with exactly this cost. Being just poor (ahem) businessmen, they have asked the Abacus Calculator Makers for help.

You are given a description of the river network with costs of river segments and a sequence of integers x1,..., xk. For each xi, you should determine if there is a pair of cities (a, b) in the river network such that the cost of the trip between a and b is exactly xi.

Input

The input consists of several instances. Each instance is described by (in the following order):

  • A single line containing a single integer: the number of villages N (1 <= N <= 10 000).
  • N lines describing the villages. The i-th of these lines (1 <= i <= N) describes the village with number i. It contains space separated integers d1, c1, d2, c2, , dki, cki, 0. The dj's are numbers of villages from which the rivers flow directly to the village i (with no other villages in between), each cj is the price of the journey between villages i and dj. Moreover, 2 <= dj <= N and 0 <= cj <= 1 000. Village 1 always corresponds to the mouth of the largest river, therefore no di can ever be equal to 1.
  • M <= 100 lines describing the queries. The i-th of these lines corresponds to the i-th query and contains a single integer xi (1 <= xi <= 10 000 000).
  • The instance is finished by a single line containing the number 0.


The whole input is ended by a single line containing the number 0.

Output

For each instance you should produce a sequence of M lines (where M is the number of queries in the particular instance). The i-th of these lines contains the word "AYE" if there exists a pair of cities in the river network which is connected by a path of cost xi, or the word "NAY" otherwise.

Output for each instance must be followed by a single line containing just the dot character.

Sample Input

6
2 5 3 7 4 1 0
0
5 2 6 3 0
0
0
0
1
8
13
14
0
0

Sample Output

AYE
AYE
NAY
AYE
.

题目大意:有n个村庄被若干条河流连接起来,各个村庄可以通过坐船互达,船行驶的距离为经过的各条河流长度和,现在有q次询问,问是否有至少一对村庄之间的距离刚好为k。

题目思路:这个题除了题目难读懂点之外,就是一个很经典的树分治题了。我们分治的过程中每次将树的重心去掉,考虑子树中的点对对答案的影响,再在合并的时候去掉重复的情况。还有就是最后要记得输出一个“.”。

具体实现看代码:

#include <algorithm>
#include  <iostream>
#include   <cstring>
#include    <cstdio>
#include    <vector>
#include     <queue>
#include       <map>
#include       <set>
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lowbit(x) x&-x
#define pb push_back
#define MP make_pair
#define clr(a) memset(a,0,sizeof(a))
#define FIN freopen("in.txt","r",stdin)
#define fuck(x) cout<<"["<<x<<"]"<<endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>pii;
const int MX=1e4+7;
const int inf=0x3f3f3f3f;

int n;
int sz[MX],dis[MX];
bool vis[MX];
int l,r,MIN;
struct edge{
	int v,w,nxt;
}E[MX<<1];
int head[MX],tot;
void init(){
	clr(vis);
	memset(head,-1,sizeof(head));
	tot=0;
}
void add_edge(int u,int v,int w){
	E[tot].v=v;E[tot].w=w;E[tot].nxt=head[u];
	head[u]=tot++;
}
void get_sz(int u,int fa){
	sz[u]=1;
	for(int i=head[u];~i;i=E[i].nxt){
		int v=E[i].v;
		if(v==fa || vis[v]) continue;
		get_sz(v,u);
		sz[u]+=sz[v];
	}
}
void get_root(int u,int fa,int num,int &rt){
	int MAX=num-sz[u];
	for(int i=head[u];~i;i=E[i].nxt){
		int v=E[i].v;
		if(v==fa || vis[v]) continue;
		get_root(v,u,num,rt);
		MAX=max(MAX,sz[v]);
	}
	if(MAX<MIN){
		MIN=MAX;
		rt=u;
	}
}
void dfs(int u,int fa,int d){
	dis[r++]=d;
	for(int i=head[u];~i;i=E[i].nxt){
		int v=E[i].v,w=E[i].w;
		if(v==fa || vis[v]) continue;
		dfs(v,u,d+w);
	}
}
int cal(int L,int R,int k){
	sort(dis+L,dis+R);
	int res=0,p=L,q=R-1;
	while(p<q){
		if(dis[p]+dis[q]==k){
			if(dis[p]==dis[q]){
				res+=(q-p+1)*(q-p)/2;
				break;
			}
			int i=p,j=q;
			while(dis[i]==dis[p]) i++;
			while(dis[j]==dis[q]) j--;
			res+=(i-p)*(q-j);
			p=i;q=j;
		} else if(dis[p]+dis[q]<k) p++;
		else q--;
	}
	return res;
}
int solve(int u,int k){
	int res=0,rt;
	MIN=inf;
	get_sz(u,0);get_root(u,0,sz[u],rt);
	vis[rt]=1;
	for(int i=head[rt];~i;i=E[i].nxt){
		int v=E[i].v;
		if(vis[v]) continue;
		res+=solve(v,k);
	}
	l=r=0;
	for(int i=head[rt];~i;i=E[i].nxt){
		int v=E[i].v,w=E[i].w;
		if(vis[v]) continue;
		dfs(v,rt,w);
		res-=cal(l,r,k);
		l=r;
	}
	res+=cal(0,r,k);
	for(int i=0;i<r;i++){
		if(dis[i]>k) break;
		if(dis[i]==k) res++;
	}
	vis[rt]=0;
	return res;
}

int main(){
	//FIN;
	while(~scanf("%d",&n)&&n){
		init();
		for(int i=1;i<=n;i++){
			int v;
			while(scanf("%d",&v)&&v){
				int d;scanf("%d",&d);
				add_edge(i,v,d);
				add_edge(v,i,d);
			}
		}
		int k;
		while(scanf("%d",&k)&&k){
			int ans=solve(1,k);
			//cout<<ans<<endl;
			printf("%s\n",ans?"AYE":"NAY");
		}
		puts(".");
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值