点分治模板 (洛谷 P3806)

传送门
学习了一下点分治。
点分治基本可以解决树上符合条件的路径的数量的问题。
流程基本上就是找重心->找不同子树上的路径->找重心。。。

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int MAXN = 1e4 + 10;
int n, m, q[110], ans[110];
int head[MAXN], to[MAXN * 2], nxt[MAXN * 2], val[MAXN * 2], tot;
int maxp[MAXN], siz[MAXN], sum, vis[MAXN], rt, temp[MAXN], cnt;
bool judge[20000010];

void add(int u, int v, int w){
    to[++tot] = v; val[tot] = w; nxt[tot] = head[u]; head[u] = tot;
}

void getrt(int u, int fa){
    siz[u] = 1, maxp[u] = 0;
    for(int i = head[u]; i; i = nxt[i]){
        if(fa == to[i] || vis[to[i]]) continue;
        getrt(to[i], u);
        siz[u] += siz[to[i]];
        maxp[u] = max(maxp[u], siz[to[i]]);
    }
    maxp[u] = max(maxp[u], sum - siz[u]);
    if(maxp[u] < maxp[rt]) rt = u;
}

void getdis(int u, int fa, int dis){
    temp[++cnt] = dis;
    for(int i = head[u]; i; i = nxt[i]){
        if(to[i] == fa || vis[to[i]]) continue;
        getdis(to[i], u, dis + val[i]);
    }
}

void solve(int u){
    queue<int> que;
    for(int i = head[u]; i; i = nxt[i]){
        if(vis[to[i]]) continue;
        cnt = 0;
        getdis(to[i], u, val[i]);
        for(int k = 1; k <= cnt; k++)
            for(int j = 1; j <= m; j++)
                if(q[j] >= temp[k]) ans[j] |= judge[q[j] - temp[k]];
        for(int k = 1; k <= cnt; k++) {
            que.push(temp[k]);
            judge[temp[k]] = 1;
        }
    }
    while(!que.empty()) judge[que.front()] = 0, que.pop();
}

void divide(int u){
    vis[u] = judge[0] = true;
    solve(u);
    for(int i = head[u]; i; i = nxt[i]){
        if(vis[to[i]]) continue;
        maxp[rt = 0] = sum = siz[to[i]];
        getrt(to[i], 0);
        getrt(rt, 0);
        divide(rt);
    }
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("data.in","r",stdin);
    freopen("data.out","w",stdout);
#endif
    scanf("%d%d", &n, &m);
    for(int i = 1, u, v, w; i < n; i++){
        scanf("%d%d%d", &u, &v, &w);
        add(u, v, w);add(v, u, w);
    }
    for(int i = 1; i <= m; i++) scanf("%d", &q[i]);
    maxp[0] = sum = n;
    getrt(1, 0);
    getrt(rt, 0);
    divide(1);
    for(int i = 1; i <= m; i++)
        printf("%s\n",ans[i] ? "AYE" : "NAY");
    return 0;
}
posted @ 2020-02-12 20:30  BakaCirno  阅读(109)  评论(0编辑  收藏  举报