目录

P3806-【模板】点分治1

P3806-【模板】点分治1

题目:

题目描述:

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

输入格式:

第一行两个数 $n,m$。

第 $2$ 到第 $n$ 行,每行三个整数 $u, v, w$,代表树上存在一条连接 $u$ 和 $v$ 边权为 $w$ 的路径。

接下来 $m$ 行,每行一个整数 $k$,代表一次询问。

输出格式:

对于每次询问输出一行一个字符串代表答案,存在输出 AYE,否则输出 NAY

样例:

样例输入1:

1
2
3
2 1
1 2 2
2

样例输出1:

1
AYE

思路:

实现:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include "ybwhead/ios.h"
const int maxn = 1e5 + 10;
struct edge
{
    int v, w, nxt;
} e[maxn << 1];
int head[maxn], tot;
void __ADD(int u, int v, int w)
{
    e[++tot].v = v;
    e[tot].w = w;
    e[tot].nxt = head[u];
    head[u] = tot;
}
void add(int u, int v, int w)
{
    __ADD(u, v, w);
    __ADD(v, u, w);
}
int n, m;
int siz[maxn], mx[maxn];
int vis[maxn], root, S;
void find(int x, int fa)
{
    siz[x] = 1;
    mx[x] = 0;
    for (int i = head[x]; i; i = e[i].nxt)
    {
        int v = e[i].v;
        if (v == fa || vis[v])
            continue;
        find(v, x);
        siz[x] += siz[v];
        mx[x] = max(siz[v], mx[x]);
    }
    mx[x] = max(S - siz[x], mx[x]);
    if (mx[x] < mx[root])
    {
        root = x;
    }
}
int a[maxn];
int d[maxn];
int b[maxn];
void get_dis(int u, int fa, int dis, int from)
{
    a[++tot] = u;
    d[u] = dis;
    b[u] = from;
    for (int i = head[u]; i; i = e[i].nxt)
    {
        int v = e[i].v;
        if (v == fa || vis[v])
            continue;
        get_dis(v, u, dis + e[i].w, from);
    }
}
bool cmp(int x, int y)
{
    return d[x] < d[y];
}
int ok[maxn];
int query[maxn];
void calc(int u)
{
    tot = 0;
    a[++tot] = u;
    d[u] = 0;
    b[u] = u; //别忘了加上root自己
    for (int i = head[u]; i; i = e[i].nxt)
    {
        int v = e[i].v;
        if (vis[v])
            continue;
        get_dis(v, u, e[i].w, v);
    }
    sort(a + 1, a + tot + 1, cmp);
    for (int i = 1; i <= m; i++)
    {
        int l = 1, r = tot;
        if (ok[i])
            continue;
        while (l < r)
        {
            if (d[a[l]] + d[a[r]] > query[i])
            {
                r--;
            }
            else if (d[a[l]] + d[a[r]] < query[i])
            {
                l++;
            }
            else if (b[a[l]] == b[a[r]])
            {
                if (d[a[r]] == d[a[r - 1]])
                    r--;
                else
                    l++;
            }
            else
            {
                ok[i] = true;
                break;
            }
        }
    }
}

void Divid(int x)
{
    vis[x] = 1;
    calc(x);
    for (int i = head[x]; i; i = e[i].nxt)
    {
        int v = e[i].v;
        if (vis[v])
            continue;
        S = siz[v];
        root = 0;
        find(v, x);
        Divid(root);
    }
}

int main()
{
    yin >> n >> m;
    for (int i = 1; i < n; i++)
    {
        int a, b, c;
        yin >> a >> b >> c;
        add(a, b, c);
    }
    for (int i = 1; i <= m; i++)
    {
        int k;
        yin >> query[i];
    }
    S = n;
    root = 0;
    mx[0] = n + 1;
    find(1, 0);
    Divid(root);
    for (int i = 1; i <= m; i++)
    {
        yout << (ok[i] ? "AYE" : "NAY") << endl;
    }
    return 0;
}