zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Android 自定义title样式
    HDU 3094 A tree game 树删边游戏
    设计模式学习笔记观察者模式
    [Unity-7] Update和FixedUpdate
    一淘搜索网页抓取系统的分析与实现(3)—scrapy+webkit &amp; mysql+django
    POJ 1947 树DP获得冠军
    linux 下一个 jira-6.3.6 组态 皴 翻译 迁移数据库
    阐述linux IPC(五岁以下儿童):system V共享内存
    使用OpenCV玩家营造出一个视频控制(没有声音)
    Swift编程语言学习4.1——周期
  • 原文地址:https://www.cnblogs.com/DriverBen/p/10963438.html
Copyright © 2011-2022 走看看