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\)

posted @ 2020-01-17 16:40  Artoriax  阅读(96)  评论(0编辑  收藏  举报