首页 > 其他 > 详细

[cdq分治][树的重心] 洛谷 P3806 点分治1

时间:2018-10-18 22:52:17      阅读:210      评论:0      收藏:0      [点我收藏+]

题目描述

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

 

代码

  • 对于一条x到y的路径有可能有两种情况,
  • ①要经过根节点,那么这样的距离就是dis[u]+dis[v](到根的距离)
  • ②在一个子树中,那么就找到该子树的根,然后就类似于第一种情况
  • 其实就是分治的思想,把树不断分解成子树然后求解
  • 点分治过程中,每一层的所有递归过程合计对每个点处理一次, 假设共递归T层,则总时间复杂度为O(TNlogN)
  • 然而,如果树退化成一条链, 那么递归层数就是T=n,总时间复杂度为O(N^2logN)
  • 这样的复杂度接受不了,那么就要减少树的层数,那么每次就要找到树的中心来作为根,这样才能减少层数
  • 然后就是点分治了

代码

 1 #include <cstdio> 
 2 #include <iostream>
 3 #include <queue>
 4 #include <vector>
 5 using namespace std;
 6 const int inf=10000000;
 7 const int N=100010;
 8 struct edge{int to,from,v;}e[N*2];
 9 int n,m,num,root,ans,cnt,head[N],mx[N],size[N],dis[N],dfn[N],vis[N],g[inf],w[inf],p[N],k[1010];
10 void insert(int x,int y,int z) { e[++cnt].to=y; e[cnt].from=head[x]; e[cnt].v=z; head[x]=cnt; }
11 void getroot(int x,int fa)
12 {
13     size[x]=1,mx[x]=0;
14     for (int i=head[x];i;i=e[i].from)
15         if (e[i].to!=fa&&!vis[e[i].to])
16         {
17             getroot(e[i].to,x);
18             size[x]+=size[e[i].to];
19             mx[x]=max(mx[x],size[e[i].to]);
20         }
21     mx[x]=max(mx[x],num-size[x]);
22     if (mx[x]<mx[root]) root=x;
23 }
24 void getdis(int x,int fa)
25 {
26     dfn[++dfn[0]]=dis[x];
27     for (int i=head[x];i;i=e[i].from) 
28         if (e[i].to!=fa&&!vis[e[i].to])
29             dis[e[i].to]=dis[x]+e[i].v,getdis(e[i].to,x);
30 }
31 void work(int x)
32 {
33     p[0]=0;
34     for (int i=head[x];i;i=e[i].from)
35         if (!vis[e[i].to])
36         {
37             dis[e[i].to]=e[i].v,dfn[0]=0;
38             getdis(e[i].to,x);
39             for (int j=dfn[0];j;j--)
40                 for (int q=1;q<=m;q++)
41                     if (k[q]>=dfn[j]) g[q]|=w[k[q]-dfn[j]];
42             for (int j=dfn[0];j;j--) p[++p[0]]=dfn[j],w[dfn[j]]=1;
43         }
44     for (int i=1;i<=p[0];i++) w[p[i]]=0;
45 }
46 void cdq(int x)
47 {
48     vis[x]=w[0]=1,work(x);
49     for (int i=head[x];i;i=e[i].from)
50         if (!vis[e[i].to])
51             num=size[e[i].to],mx[root=0]=inf,getroot(e[i].to,0),cdq(root);
52 }
53 int main() 
54 {
55     scanf("%d%d",&n,&m);
56     for (int i=1,x,y,z;i<n;i++) scanf("%d%d%d",&x,&y,&z),insert(x,y,z),insert(y,x,z);
57     for (int i=1;i<=m;i++) scanf("%d",&k[i]);
58     mx[root]=num=n,getroot(1,0),cdq(root);
59     for (int i=1;i<=m;i++) if (g[i]) printf("AYE\n"); else printf("NAY\n");
60 }

 

[cdq分治][树的重心] 洛谷 P3806 点分治1

原文:https://www.cnblogs.com/Comfortable/p/9813348.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!