P3806 【模板】点分治 1——模板

【模板】点分治 1

题目背景

感谢 hzwer 的点分治互测。

题目描述

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

输入格式

第一行两个数 \(n,m\)

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

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

输出格式

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

样例 #1

样例输入 #1

2 1
1 2 2
2

样例输出 #1

AYE

提示

数据规模与约定

  • 对于 \(30\%\) 的数据,保证 \(n\leq 100\)
  • 对于 \(60\%\) 的数据,保证 \(n\leq 1000\)\(m\leq 50\)
  • 对于 \(100\%\) 的数据,保证 \(1 \leq n\leq 10^4\)\(1 \leq m\leq 100\)\(1 \leq k \leq 10^7\)\(1 \leq u, v \leq n\)\(1 \leq w \leq 10^4\)

提示

  • 本题不卡常
  • 如果您 #7 一直 RE/TLE,不妨看看 这个帖子

codes

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+100;
const long long M=1e9+100;
struct edge{int y,x,n,z;}e[N<<1];

int n,m,cnt,head[N],q[N],top,lim;
int siz[N],mxa[N],root,all,dis[N],r[110],ans[110],qu[N];
int tot[10000010],las[10000010];
bool vis[N];
void ad(int x,int y,int z)
{
    e[++cnt].n=head[x];
    e[cnt].y=y;
    e[cnt].x=x;
    e[cnt].z=z;
    head[x]=cnt;
}

void init()
{
    scanf("%d%d",&n,&m);

    for(int i=1,x,y,z;i<n;++i)
    {
        scanf("%d%d%d",&x,&y,&z);
        ad(x,y,z);ad(y,x,z);
        las[z]=1;
    }

    for(int i=1;i<=m;++i)
    {
        scanf("%d",&r[i]);
        lim=max(lim,r[i]);
    }
}

void getrt(int u,int fa)
{
    siz[u]=1;
    mxa[u]=0;
    for(int i=head[u];i;i=e[i].n)
    {
        int v=e[i].y;
        if(v==fa || vis[v])continue;
        getrt(v,u);
        siz[u]+=siz[v];
        mxa[u]=max(mxa[u],siz[v]);
    }
    mxa[u]=max(mxa[u],all-siz[u]);
    if(mxa[u]<mxa[root])root=u;
}

void getdis(int u,int fa)
{
    q[++q[0]]=dis[u];
    for(int i=head[u];i;i=e[i].n)
    {
        int v=e[i].y;
        if(vis[v] || v==fa)continue;
        dis[v]=dis[u]+e[i].z;
        getdis(v,u);
    }
}

void calc(int u)
{
    int num=0;
    for(int i=head[u];i;i=e[i].n)
    {
        int v=e[i].y;
        if(vis[v])continue;
        dis[v]=e[i].z;
        q[0]=0;
        getdis(v,0);
        for(int j=1;j<=q[0];++j)
        {
            for(int k=1;k<=m;++k)
                if(r[k] >= q[j])
                    ans[k]|=(tot[r[k]-q[j]]>0);
        }
        for(int j=1;j<=q[0];++j)
            qu[++num]=q[j],tot[q[j]]=1;
    }

    for(int i=1;i<=num;++i)
        tot[qu[i]]=0;

}

void solve(int nw)
{
    vis[nw]=tot[0]=1;
    calc(nw);
    for(int i=head[nw];i;i=e[i].n)
    {
        int v=e[i].y;
        if(vis[v])continue;
        all=siz[v];
        root=0;
        mxa[root]=M;
        getrt(v,0);
        solve(root);
    }

}

void work()
{

    mxa[root]=M;
    getrt(1,0);
    solve(root);

    for(int i=1;i<=m;++i,putchar('\n'))
        if(ans[i])cout<<"AYE";
        else cout<<"NAY";
}

int main()
{
    init();
    work();
    return 0;
}










posted @ 2024-11-05 21:05  Glowingfire  阅读(4)  评论(0编辑  收藏  举报