这道题目和楼教男人八题中的Tree差不多。只不过那到题目求小于k的个数,而这道题目求是否存在等于k。
具体做法也是类似,点分治。在QZC的《分治算法在树的路径问题中的应用》中有讲解,不过大牛们的思路跳跃比较大,讲的比较简单,具体可参考这篇文章。
首先理解“树的重心”,然后如何分治,如何去重,最后如何O(n)的求点对。理解复杂度为N*log2N,还是重在理解。
在这道题中注意:
如果A[i]+A[j]==k,先要判断A[j]是否等于A[j-1],若等于j--,否则i++。比如当前求得序列:1,2,2,要求的k为3,如果A[i]+A[j]<=k,就让i++,求得结果是1,而实际是2。在这个地方WA了几次。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
const int maxn = 10010;
int head[maxn], dp[maxn], Q[maxn][2], V[maxn];
bool vis[maxn];
int n, k[110], ans[110], cnt, tot, size, gn, M;
struct EDG{
int v, c, next;
}g[maxn << 1];
void add(int u, int v, int c)
{
g[cnt].v = v; g[cnt].c = c; g[cnt].next = head[u]; head[u] = cnt++;
}
int dfs(int u, int p, int m)
{
dp[u] = 1;
int sz = 0;
for(int e = head[u]; e != -1; e = g[e].next){
int v = g[e].v;
if(v != p && !vis[v]){
int z = dfs(v, u, m);
sz = max(sz, z);
dp[u] += z;
}
}
sz = max(sz, m - dp[u]);
if(size > sz){
size = sz;
gn = u;
}
return dp[u];
}
void Dp(int u, int p, int d)
{
V[tot++] = d;
for(int e = head[u]; e != -1; e = g[e].next){
int v = g[e].v;
if(v != p && !vis[v]){
Dp(v, u, d + g[e].c);
}
}
}
void count(int v)
{
sort(V, V + tot);
for(int i = 0; i < M; i++){
int l = 0, r = tot - 1;
while(l < r){
if(V[l] + V[r] < k[i]){
l++;
}else if(V[l] + V[r] == k[i]){
ans[i] += v;
if(V[r] == V[r - 1]) r--;
else l++;
}else r--;
}
}
}
int main()
{
int n;
int u, c;
while(scanf("%d", &n) == 1 && n){
memset(head, 0xff, sizeof(head));
memset(vis, 0, sizeof(vis));
cnt = 0;
for(int i = 1; i <= n; i++){
while(scanf("%d", &u) == 1 && u){
scanf("%d", &c);
add(i, u, c);
add(u, i, c);
}
}
M = 0;
while(scanf("%d", &u) == 1 && u){
ans[M]= 0;
k[M++] = u;
}
int f = 0, r = 0;
Q[0][0] = 1, Q[0][1] = n;
while(f <= r){
size = maxn;
dfs(Q[f][0], Q[f][0], Q[f][1]);
tot = 0;
vis[gn] = true;
Dp(gn, gn, 0);
count(1);
for(int e = head[gn]; e != -1; e = g[e].next){
int v = g[e].v;
if(!vis[v]){
r++;
Q[r][0] = v, Q[r][1] = dp[v];
tot = 0;
Dp(v, gn, g[e].c);
count(-1);
}
}
f++;
}
for(int i = 0; i < M; i++)
printf("%s\n", ans[i] > 0 ? "AYE" : "NAY");
printf(".\n");
}
return 0;
}