[cdq分治][树的重心] 洛谷 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

 

代码

  • 对于一条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 }

 

posted @ 2018-10-18 21:32  BEYang_Z  阅读(180)  评论(0编辑  收藏  举报