【模板】点分治1

传送门:洛谷P3806


题目描述

给定一棵有n个点的树
询问树上距离为k的点对是否存在。


分析

瞥了几眼数据,貌似可以开数组的样子,于是,,,,,,,
直接参考tree的做法.calc时,两重循环枚举能够得到的距离,用桶当计数器即可


代码

#include <cstdio>
#include <cstdlib>
#include <cstring>

#define IL inline
#define open(s) freopen(s".in","r",stdin); freopen(s".out","w",stdout);
#define close fclose(stdin); fclose(stdout);

using namespace std;

IL int read()
{
    char c = getchar();
    int sum = 0 ,k = 1;
    for(;'0' > c || c > '9'; c = getchar())
        if(c == '-') k = -1;
    for(;'0' <= c && c <= '9'; c = getchar()) sum = sum * 10 + c - '0';
    return sum * k;
}

struct Edge
{
    int to, nxt, w;
    IL Edge(int to_ = 0, int nxt_ = 0, int w_ = 0)
    {
        to = to_; nxt = nxt_; w = w_;
    }
}edge[20005];
int cnt;
int last[10005];
IL void add(int x, int y, int w)
{
    edge[++cnt] = Edge(y, last[x], w); last[x] = cnt;
    edge[++cnt] = Edge(x, last[y], w); last[y] = cnt;
}

int maxw;
int n, m;
int tot;
int qes[105];
int ans[10000005];
int dis[10005];
int size[10005];
bool use[10005];

IL void get_root(int u, int pre, int &root, int &k, int sz)
{
    size[u] = 1;
    int tmp = 0;
    for(int i = last[u], v; i; i = edge[i].nxt)
    if(!use[edge[i].to] && edge[i].to != pre)
    {
        v = edge[i].to;
        get_root(v, u, root, k, sz);
        if(size[v] > tmp) tmp = size[v];
        size[u] += size[v];
    }
    if(sz - size[u] > tmp) tmp = sz - size[u];
    if(tmp < k) { k = tmp; root = u;}
}

IL void get_dis(int u, int pre, int d)
{
    if(d > maxw) return ;
    dis[++tot] = d;
    for(int i = last[u]; i; i = edge[i].nxt)
    if(!use[edge[i].to] && edge[i].to != pre)
        get_dis(edge[i].to, u, d + edge[i].w);
}

IL void calc(int u, int d, int k)
{
    tot = 0;
    get_dis(u, 0, d);
    for(int i = 1; i < tot; ++i)
    for(int j = i + 1; j <= tot; ++j)
    if(dis[i] + dis[j] <= maxw)
        ans[dis[i] + dis[j]] += k;
}

IL void solve(int p, int sz)
{
    int root = -1, k = sz;
    get_root(p, p, root, k, sz);
    use[root] = 1;
    calc(root, 0, 1);
    for(int i = last[root], v; i; i = edge[i].nxt)
    if(!use[edge[i].to])
    {
        v = edge[i].to;
        calc(v, edge[i].w, -1);
        solve(v, size[v]);
    }
}

int main()
{
    open("3806")

    n = read(); m = read();
    for(int i = 1, x, y; i < n; ++i)
    {
        x = read(); y = read();
        add(x, y, read());
    }

    for(int i = 1; i <= m; ++i)
    {
        qes[i] = read();
        if(qes[i] > maxw) maxw = qes[i];
    }
    solve(1, n);

    ans[0] = 1;
    for(int i = 1; i <= m; ++i)
        printf("%s\n", ans[qes[i]] ? "AYE" :"NAY");

    close
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_27121257/article/details/81228681