POJ 2114 Boatherds
点分治
题意
给一棵带边权的树,给一系列询问,问是否存在一条路径,使得路上权值和恰好为K。
思路
点分治。
100个询问,每次做一遍点分治。点分治记录所有路径长度,在二分查找是否有满足条件的长度。
代码
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int MAXN=20005;
struct Edge
{
int to, ne;
int w;
}e[MAXN*2+7];
int edgenum, head[MAXN];
void addedge(int from, int to, int w)
{
e[edgenum].to=to, e[edgenum].w=w, e[edgenum].ne=head[from], head[from]=edgenum++;
e[edgenum].to=from, e[edgenum].w=w, e[edgenum].ne=head[to], head[to]=edgenum++;
}
int sz[MAXN], mx[MAXN], root, vis[MAXN];
void getrt(int x, int f, int n)//找x的子树内的重心root
{
sz[x]=1;mx[x]=0;
for(int i=head[x];~i;i=e[i].ne)
{
int to=e[i].to;
if(to==f||vis[to]) continue;
getrt(to, x, n);
sz[x]+=sz[to];
mx[x]=max(mx[x], sz[to]);
}
mx[x]=max(mx[x], n-sz[x]);
if(mx[x]<mx[root]) root=x;
}
int dis[MAXN], discnt;
int d[MAXN];
void getdis(int x, int f)
{
dis[discnt++]=d[x];
for(int i=head[x];~i;i=e[i].ne)
{
int to=e[i].to;
if(to==f||vis[to]) continue;
d[to]=(d[x]+e[i].w);
getdis(to, x);
}
}
int calc(int x, int nowd, int k)
{
discnt=0;
d[x]=nowd;
getdis(x, -1);
int cnt=0;
sort(dis, dis+discnt);
for(int i=0;i<discnt;i++)
{
if(dis[i]+dis[i]>k) break;
int yu=k-dis[i];
int l=i+1, r=discnt-1;
int resl=0, resr=-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(dis[mid]==yu) r=mid-1, resl=mid;
else if(dis[mid]<yu) l=mid+1;
else r=mid-1;
}
l=i+1, r=discnt-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(dis[mid]==yu) l=mid+1, resr=mid;
else if(dis[mid]<yu) l=mid+1;
else r=mid-1;
}
cnt+=(resr-resl+1);
}
return cnt;
}
int ans;
void work(int x, int k)
{
vis[x]=1;
ans+=calc(x, 0, k);
for(int i=head[x];~i;i=e[i].ne)
{
if(vis[e[i].to]) continue;
ans-=calc(e[i].to, e[i].w, k);
root=0;
getrt(e[i].to, -1, sz[e[i].to]);
work(root, k);
}
}
int main()
{
int n=0;
while(scanf("%d", &n)==1&&n)
{
memset(head, -1, sizeof(head));
edgenum=0;
for(int i=1;i<=n;i++)
{
int a, b;
while(scanf("%d", &a)==1&&a)
{
scanf("%d", &b);
addedge(i, a, b);
}
}
int q, qcnt=0;
while(scanf("%d", &q)==1&&q)
{
memset(vis, 0, sizeof(vis));
discnt=0;
mx[0]=0x3f3f3f3f;ans=0;root=0;
getrt(1, -1, n);
work(root, q);
//printf("%d\n", ans);
printf("%s\n", ans>0 ? "AYE" : "NAY");
}
puts(".");
}
return 0;
}