题目描述
给定一棵有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
扫描二维码关注公众号,回复:
1576846 查看本文章
对于100%的数据n<=10000,m<=100,c<=1000,K<=10000000
题解
刚刚学了点分治,感觉其实不是很难,处理关于树上两点之间的路径的问题,思想是每次寻找树的重心,
之后开始不断向子树递归。
代码
#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN = 100010;
int n,m,head[MAXN],cnt,tt;
int pp; //以同一个点为根的子树编号
int sum; //子树的总点数
int rt; //当前的子树的根
int d[MAXN]; //i到当前根的距离
int f[MAXN],son[MAXN]; //f为除去根得到的最大联通块,son为以i为根的子树的节点
bool vis[MAXN],ko[10000005]; //k是否存在
struct Edge{
int nxt,to,w;
}edge[MAXN*2];
struct Node{
int dis,which;
}node[MAXN];
inline void add(int bg,int ed,int v){
edge[++cnt].to=ed;
edge[cnt].nxt=head[bg];
edge[cnt].w=v;
head[bg]=cnt;
}
inline void getroot(int u,int fa){ //找重心
son[u]=1;f[u]=0;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(vis[v] || v==fa) continue;
getroot(v,u);
son[u]+=son[v];
f[u]=max(f[u],son[v]);
}
f[u]=max(f[u],sum-son[u]);
rt=f[u]<f[rt]?u:rt;
}
inline void getdeep(int rearoot,int u,int fa,int ro){ //得到点到根的距离。
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(vis[v] || v==fa) continue;
d[v]=d[u]+edge[i].w;
ko[d[v]]=1;
if(u==rearoot) {
node[++tt].dis=d[v];
node[tt].which=++pp;
getdeep(rearoot,v,u,pp);
}
else{
node[++tt].dis=d[v];
node[tt].which=ro;
getdeep(rearoot,v,u,ro);
}
}
}
inline void getans(int u){
d[u]=0;tt=0;pp=0;
getdeep(u,u,0,0);
vis[u]=1;
for(register int i=1;i<=tt;i++)
for(register int j=i+1;j<=tt;j++)
if(node[i].which!=node[j].which)
ko[node[i].dis+node[j].dis]=1;
for(register int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(vis[v]) continue;
rt=0;sum=son[v];
getroot(v,0);
getans(rt);
}
}
int main(){
scanf("%d%d",&n,&m);
for(register int i=1;i<n;i++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);add(b,a,c);
}
sum=f[0]=n;
rt=0;
getroot(1,0); //找重心。
getans(rt); //以重心建树。
for(register int i=1;i<=m;i++){
int kk;
scanf("%d",&kk);
if(ko[kk]==1) printf("AYE\n");
else printf("NAY\n");
}
return 0;
}