• 【模板++】点分治


    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%汪神

     P3806 【模板】点分治1

    题目描述

    给定一棵有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

    这道和上一道略有不同,是计算刚好等于k的点对是否存在,同时还是多组数据。我们只需要找一次,记录所有的点对距离,之后每输入一个k直接判断就好。

    **本题重点**

    可能会有算重的情况,如下:

    代码里巧妙地用ad来表示+1还是-1。这种表示方法要记住,以后应该还会用得到。

     1 #include <iostream>
     2 #include <cmath>
     3 #include <cstring>
     4 #include <cstdio>
     5 #include <cstdlib>
     6 #include <algorithm>
     7 #define MAXN 10010
     8 using namespace std;
     9 long long m,k,ans[20101010],ff[20010];
    10 int cnt,root,sn,tot;
    11 int first[MAXN],to[20010],len[20010],next[20010],son[MAXN],deep[MAXN],vis[MAXN],f[MAXN],d[MAXN];
    12 void add(int x,int y,int z)  //建立邻接表
    13 {
    14     to[++cnt]=y;len[cnt]=z;  //to数组是当前边的下一条边的编号 
    15     next[cnt]=first[x];  //next数组记录当前起始点的前一条边的编号
    16     first[x]=cnt;  //first最终记录的是当前点作为起始点的最后一条边,之后从后往前遍历
    17 }
    18 void get_root(int x,int fa)  //找重心
    19 {
    20     f[x]=0,son[x]=1; //f数组记录以x为根最大子树的大小
    21     for(int i=first[x];i;i=next[i])
    22         if(to[i]!=fa && !vis[to[i]])  //不用考虑根节点以及没有访问过 
    23         {
    24             get_root(to[i],x);
    25             son[x]+=son[to[i]];  //计算x结点大小
    26             f[x]=max(f[x],son[to[i]]);  //找到最大子树
    27         }
    28         f[x]=max(f[x],sn-son[x]);
    29         if(f[root]>f[x]) root=x;  //更新当前根
    30 }
    31 void get_deep(int x,int fa)  //求当前x为根节点的树的深度
    32 {
    33     d[++tot]=deep[x];  //每两个点之间的距离值都要记录
    34     ff[tot]=x;
    35     for(int i=first[x];i;i=next[i])
    36         if(to[i]!=fa && !vis[to[i]])
    37         {
    38             deep[to[i]]=deep[x]+len[i];
    39             get_deep(to[i],x);
    40         }
    41 }
    42 void calc(int x,int ad)
    43 {
    44     tot=0;
    45     get_deep(x,0);
    46     int i=1,j=tot,sum=0;
    47     for(int i=1;i<tot;i++)  //求个数 
    48     {
    49         for(int j=i+1;j<=tot;j++)
    50         {
    51             if(ff[i]!=ff[j]) ans[d[i]+d[j]]+=ad;
    52         }
    53     }
    54 
    55 }
    56 void dfs(int x)
    57 {
    58     deep[x]=0;
    59     vis[x]=1;
    60     calc(x,1);
    61     for(int i=first[x];i;i=next[i])
    62     { 
    63         if(!vis[to[i]])  //**//
    64         {
    65             calc(to[i],-1);
    66             deep[to[i]]=len[i];
    67             sn=son[to[i]];
    68             root=0;
    69             get_root(to[i],0);
    70             dfs(root);
    71         }
    72     } 
    73 }
    74 int main()
    75 {
    76     int n,x,y,z;
    77     scanf("%d%lld",&n,&m);
    78     memset(first,0,sizeof(first));
    79     memset(vis,0,sizeof(vis));
    80     cnt=0;
    81     for(int i=1;i<n;i++)
    82     {
    83         scanf("%d%d%d",&x,&y,&z);
    84         add(x,y,z);  //无向图,建两次 
    85         add(y,x,z);
    86     }
    87     f[0]=0x7fffffff;sn=n;
    88     root=0;get_root(1,0);dfs(root);
    89     for(int i=1;i<=m;i++)
    90     {
    91            scanf("%lld",&k);
    92         if(ans[k]>0) printf("AYE
    ");
    93         else printf("NAY
    ");
    94     }
    95     return 0;
    96 }
    P3806
  • 相关阅读:
    servlet技术学习随笔
    python使用openpyxl读取excel文件
    课后作业-阅读任务-阅读提问-3
    课后作业-阅读任务-阅读提问-2
    课后作业-阅读任务-阅读笔记3
    构建之法:现代软件工程-阅读笔记2
    《构建之法:现代软件工程-阅读笔记》
    结对编程需求分析
    团队-团队编程项目作业名称-需求分析
    团队-团队编程项目作业名称-成员简介及分工
  • 原文地址:https://www.cnblogs.com/YXY-1211/p/8183799.html
Copyright © 2020-2023  润新知