点分治

思想

点分治的思想其实就是在树上进行分治。从而降低复杂度。
每次找到一个点,对其进行处理,然后删除这个点,对剩下的子树进行递归处理。
因为重心的每个儿子的大小不超过\(\frac{n}{2}\),所以如果这个点是重心的话,就可保证递归层数最多为log层。

实现

在弄懂点分治思想的情况下,点分治的代码还是比较好写的。虽然码量不小,但是思路比较显然。细节较多。
有时候重心会比较难找(或者懒得找重心),可以\(rand\)一个点作为根。出题人一般不会卡掉的。

例题

luogu3860

思路

点分治的模板题。对于当前的树,统计出当前每个点到根的距离,然后看是否有两个距离相加为K。注意在同一棵子树中的点是不行的。所以应该处理一下。方法有很多。我是将之前子树的距离和当前子树的距离分开。然后用双指针去拼K。
如果递归m次可能会无法承受。所以可以在每次递归的时候都统计一下每个询问的答案。
这个题数据可能比较水,没有找重心一样能过去

代码

/*
* @Author: wxyww
* @Date:   2019-01-30 08:05:27
* @Last Modified time: 2019-01-30 09:41:38
*/
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N = 10010;
ll read() {
    ll x=0,f=1;char c=getchar();
    while(c<'0'||c>'9') {
        if(c=='-') f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9') {
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}
int n,m;
struct node {
    int v,nxt,w;
}e[N << 1];
int que[N],ans[N];
int head[N],ejs;
void add(int u,int v,int w) {
    e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;e[ejs].w = w;
}
int rt;
int dis[N],js;
void dfs(int u,int father,int dist) {
    dis[++js] = dist;
    for(int i = head[u];i;i = e[i].nxt) {
        int v = e[i].v;if(v == father) continue;
        dfs(v,u,dist + e[i].w);
    }
}
void solve(int u,int father) {
    int rt = u;
     int now = 0;js = 0;
    for(int i = head[rt];i;i = e[i].nxt) {
        int v = e[i].v;if(v == father) continue;
        dfs(v,u,e[i].w);
        sort(dis + 1,dis + now + 1);sort(dis + now + 1,dis + js + 1);
        for(int i = 1;i <= m;++i) {
            int l = 0,r = js;
            while(l <= now && r > now) {
                while(dis[l] + dis[r] < que[i] && l <= now && r > now) ++l;
                while(dis[l] + dis[r] > que[i] && l <= now && r > now) --r;
                if(dis[l] + dis[r] == que[i] && l <= now && r > now) {
                    ans[i] = 1;break;
                }
            } 
        }
        now = js;
    }
    for(int i = head[rt];i;i = e[i].nxt) {
        int v = e[i].v;if(v == father) continue;
        solve(v,rt);
    }
}
int main() {
    n = read();m = read();
    for(int i = 1;i < n;++i) {
        int u = read(),v = read(),w = read();
        add(u,v,w);add(v,u,w);
    }
    for(int i = 1;i <= m;++i) que[i] = read();
    solve(1,0);
    for(int i = 1;i <= m;++i) {
        if(ans[i]) puts("AYE");
        else puts("NAY"); 
    }
    return 0;
}

你可能感兴趣的:(点分治)