题目描述
给定一棵有n个点的树
询问树上距离为k的点对是否存在。
输入输出格式
输入格式:
n,m 接下来n-1条边a,b,c描述a到b有一条长度为c的路径
接下来m行每行询问一个K
输出格式:
对于每个K每行输出一个答案,存在输出“AYE”,否则输出”NAY”(不包含引号)
输入输出样例
说明
对于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 "); else printf("NAY "); 60 }