POJ-2114 Boatherds
题面
太长了不放了
链接:https://vjudge.net/problem/POJ-2114
题意
给定一颗树,m次询问,每次询问是否有路径长度为k的树
题解
和上题差不多,我们可以顺便把路径长度等于k的路径有多少条也算出来,大于0就有,等于0就没有
方法也是和上题一样,这题可以先合并长度相等的路径,然后two pointer扫一遍
代码
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 1e5 + 50;
typedef long long ll;
const int inf = 0x3f3f3f3f;
struct node {
int v; ll w;
node(int v = 0, ll w = 0): v(v), w(w) {}
};
struct D {
ll val, len;
} a[N * 10];
vector<node> G[N];
int sze[N];
int msze[N];
int S;
int root;
int maxx;
int vis[N];
void getroot(int u, int f) {
sze[u] = 1;
msze[u] = 0;
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i].v;
if (v == f || vis[v]) continue;
getroot(v, u);
sze[u] += sze[v];
msze[u] = max(msze[u], sze[v]);
}
msze[u] = max(msze[u], S - sze[u]);
if (maxx > msze[u]) {
root = u;
maxx = msze[u];
}
}
int dis[N * 10];
int cnt = 0;
void getdis(int u, int f, int d) {
dis[++cnt] = d;
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i].v;
if (v == f || vis[v]) continue;
getdis(v, u, d + G[u][i].w);
}
}
ll k;
ll calc(int u, ll w) {
cnt = 0;
getdis(u, 0, w);
sort(dis + 1, dis + cnt + 1);
int num = 0;
dis[0] = -1;//这里注意,要不第一个dis[1]为0时会出现错误
for (int i = 1; i <= cnt; i++) {
if (dis[i] != dis[i - 1]) {
a[++num].val = dis[i];
a[num].len = 1;
}
else a[num].len++;
}
ll ans = 0;
int l = 1, r = num;
while (l <= r) {
if (a[l].val + a[r].val == k) {
if (l == r) {
ans += a[l].len * (a[l].len - 1) / 2;
return ans;
}
ans += a[l].len * a[r].len;
l++, r--;
}
else if (a[l].val + a[r].val < k) l++;
else r--;
}
return ans;
}
ll ans;
void dfs(int u) {
ans += calc(u, 0);
vis[u] = 1;
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i].v;
if (vis[v]) continue;
ans -= calc(v, G[u][i].w);
S = sze[v];
root = 0;
maxx = inf;
getroot(v, 0);
dfs(root);
}
}
int main() {
int n;
while (scanf("%d", &n) && n) {
for (int i = 1; i <= n; i++) G[i].clear();
for (int i = 1; i <= n; i++) {
int v;
while (scanf("%d", &v) && v) {
ll w;
scanf("%lld", &w);
G[i].push_back(node(v, w));
G[v].push_back(node(i, w));
}
}
while (scanf("%lld", &k) && k) {
for (int i = 1; i <= n; i++) {
vis[i] = 0;
sze[i] = 0;
msze[i] = 0;
cnt = 0;
}
S = n;
root = 0;
maxx = inf;
getroot(1, 0);
ans = 0;
dfs(root);
if (ans > 0) puts("AYE");
else puts("NAY");
}
puts(".");
}
return 0;
}
这题re两发,不是因为数组开小,也不是因为别的什么,而是把\(G[u][i].v\)写成\(G[u][i].w\)