[模板] 点分治

Posted dukelv

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[模板] 点分治相关的知识,希望对你有一定的参考价值。

之前搞了一个树的中心,结果当时把点分治给扔下了,现在搞一搞。其实点分治的分治思想很明显,就是把树切成一个个小树,然后在重心的位置再分治就行了。

代码实现有一定困难,但就我觉得前一个函数和树刨的dfs1很像吗,详情见代码。

题干:

题目背景

感谢hzwer的点分治互测。
题目描述
给定一棵有n个点的树
询问树上距离为k的点对是否存在。
输入输出格式
输入格式:
n,m 接下来n-1条边a,b,c描述a到b有一条长度为c的路径
接下来m行每行询问一个K
输出格式:
对于每个K每行输出一个答案,存在输出“AYE”,否则输出”NAY”(不包含引号)
输入输出样例
输入样例#1: 复制
2 1
1 2 2
2
输出样例#1: 复制
AYE
说明
对于30%的数据n<=100
对于60%的数据n<=1000,m<=50
对于100%的数据n<=10000,m<=100,c<=1000,K<=10000000

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(int i = a;i <= n;i++)
#define lv(i,a,n) for(int i = a;i >= n;i--)
#define clean(a) memset(a,0,sizeof(a))
const int INF = 1 << 30;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
    char c;
    bool op = 0;
    while(c = getchar(), c < 0 || c > 9)
        if(c == -) op = 1;
    x = c - 0;
    while(c = getchar(), c >= 0 && c <= 9)
        x = x * 10 + c - 0;
    if(op) x = -x;
}
template <class T>
void write(T x)
{
    if(x < 0) putchar(-), x = -x;
    if(x >= 10) write(x / 10);
    putchar(0 + x % 10);
}
struct node
{
    int l,r,nxt,w;
} a[40005];
int lst[40005],len = 0,n,m;
void add(int x,int y,int w)
{
    a[++len].l = x;
    a[len].r = y;
    a[len].w = w;
    a[len].nxt = lst[x];
    lst[x] = len;
}
int qu[405],maxp[40005],sum,rt = 0,siz[40005];
int vis[40005],judge[10000000],test[10000000];
int q[40005],dis[40005],rem[40005];
void getrt(int u,int pa)
{
    siz[u] = 1;
    maxp[u] = 0;
    for(int k = lst[u]; k; k = a[k].nxt)
    {
        int y = a[k].r;
        if(y == pa || vis[y])
            continue;
        getrt(y,u);
        siz[u] += siz[y];
        maxp[u] = max(maxp[u],siz[y]);
    }
    maxp[u] = max(maxp[u],sum - siz[u]);
    if(maxp[u] < maxp[rt])
        rt = u;
}
void getdis(int u,int fa)
{
    rem[++rem[0]] = dis[u];//主要是这一句,就是rem中存了所有可能的长度 
    for(int k = lst[u]; k; k = a[k].nxt)
    {
        int y = a[k].r;
        if(y == fa || vis[y] == 1)
            continue;
        dis[y] = dis[u] + a[k].w;//记录子树中的距离 
        getdis(y,u);
    }
}
void calc(int u)
{
    int p = 0;
    for(int k = lst[u]; k; k = a[k].nxt)
    {
        int y = a[k].r;
        if(vis[y] == 1)
            continue;
        rem[0] = 0;
        dis[y] = a[k].w;
        getdis(y,u);
        lv(j,rem[0],1)
        {
            duke(i,1,m)
            {
                if(qu[i] >= rem[j])
                    test[i] |= judge[qu[i] - rem[j]];//尝试匹配 
            }
        } 
        lv(j,rem[0],1)
        {
            q[++p] = rem[j];//就是一个过程量 
            judge[rem[j]] = 1;
        } 
    } 
    duke(i,1,p)
    judge[q[i]] = 0;//清空当前子树judge数组 
}
void solve(int u)
{
    vis[u] = judge[0] = 1;
    calc(u);
    for(int k = lst[u]; k; k = a[k].nxt)
    {
        int y = a[k].r;
        if(vis[y])
            continue;
        sum = siz[y];
        maxp[rt = 0] = INF;
        getrt(y,0);
        solve(rt);
    }
}
int main()
{
    read(n);
    read(m);
    duke(i,1,n - 1)
    {
        int x,y,w;
        read(x);
        read(y);
        read(w);
        add(x,y,w);
        add(y,x,w);
    }
    duke(i,1,m)
    read(qu[i]);
    maxp[rt] = sum = n;
    getrt(1,0);
//    cout<<"QAQ"<<endl; 
    solve(rt);
    duke(i,1,m)
    {
        if(test[i])
            printf("AYE
");
        else
            printf("NAY
");
    }
    return 0;
}

 

以上是关于[模板] 点分治的主要内容,如果未能解决你的问题,请参考以下文章

点分治模板理解

[P3806] 模板点分治 - 点分治

LuoguP3806 模板点分治1 (点分治)

洛谷.3806.[模板]点分治1(点分治)

模板点分治

luoguP3806 模板点分治1 [点分治]