P3806 模板点分治1

Posted driverben

tags:

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

题目背景

感谢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<=10000,K<=10000000

代码

对于每个点,分为有长度为k的路径经过点以及长度为k的路径在其子树

对于长度为k的路径在其子树的点,我们可以将其看作是长度为k的路径经过其子树所在根节点

那么这就是点分治的基本思想

为降低复杂度,我们每次采取重心作为根节点。将树的深度将至logn

则复杂度为O(NlogN2)

 

技术图片
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=10000+100,maxm=10000000+100;
int head[maxn];
int q[maxn],ans[maxn];
int p[maxm],t[maxn];
int d[maxn],dis[maxn],vis[maxn];
int s[maxn],ms[maxn];
int rt=0,sum;
int n,m;
struct edge

    int to,next,val;
e[maxn<<1];
int size=0;
inline int read()

    int x=0,f=1;char ch=getchar();
    while(ch<0||ch>9)if(ch==-)f=-1;ch=getchar();
    while(ch>=0&&ch<=9)x=(x<<3)+(x<<1)+ch-0;ch=getchar();
    return x*f;

void addedge(int u,int v,int w)

    e[++size].to=v;e[size].val=w;e[size].next=head[u];head[u]=size;

void tc(int u,int fa)//树的重心 

    s[u]=1;ms[u]=0;
    for(int i=head[u];i;i=e[i].next)
    
        int to=e[i].to;
        if(to==fa||vis[to])continue;
        tc(to,u);
        s[u]+=s[to];
        ms[u]=max(ms[u],s[to]);
    
    ms[u]=max(ms[u],sum-ms[u]);
    if(ms[u]<ms[rt])rt=u;

void dfs(int u,int fa)

    d[++d[0]]=dis[u];
    for(int i=head[u];i;i=e[i].next)
    
        int to=e[i].to;
        if(to==fa||vis[to])continue;
        dis[to]=dis[u]+e[i].val;
        dfs(to,u);
    

void cal(int u)

    int tot=0;
    for(int i=head[u];i;i=e[i].next)
    
        int to=e[i].to;
        if(vis[to])continue;
        d[0]=0;dis[to]=e[i].val;
        dfs(to,u);
        for(int j=1;j<=d[0];++j)
        for(int k=1;k<=m;++k)
        if(!ans[k]&&q[k]>=d[j])//有长度为q[k]的路径:该子树与之前其他子树距离和为q[k]
        ans[k]=p[q[k]-d[j]];
        for(int j=1;j<=d[0];++j)
        t[++tot]=d[j],p[d[j]]=1;//用桶存下到该节点已有的距离 
    
    for(int i=1;i<=tot;i++)
    p[t[i]]=0;//桶清空,用memsetTLE 

void solve(int u)

    vis[u]=p[0]=1;cal(u);
    for(int i=head[u];i;i=e[i].next)
    
        int to=e[i].to;
        if(vis[to])continue;
        sum=s[to],ms[rt=0]=inf;
        tc(to,0);solve(rt);
    

int main()

    n=read(),m=read();
    for(int i=1;i<n;i++)
    
        int u=read(),v=read(),w=read();
        addedge(u,v,w);
        addedge(v,u,w);
    
    for(int i=1;i<=m;i++)
    q[i]=read();
    sum=n;ms[rt]=inf;
    tc(1,0);
    solve(rt);
    for(int i=1;i<=m;i++)
    puts(ans[i]?"AYE":"NAY");
    return 0;
View Code

 

 

 

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

P3806 模板点分治1

Luogu P3806 模板点分治1

P3806 模板点分治1

洛谷P3806 模板点分治1

P3806 模板点分治1

刷题洛谷 P3806模板点分治1