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  阅读(37)  评论(0)    收藏  举报