洛谷 P3806 【模板】点分治1
题目描述
给定一棵有 nn 个点的树,询问树上距离为 kk 的点对是否存在。
输入格式
第一行两个数 n,mn,m。
第 22 到第 nn 行,每行三个整数 u, v, wu,v,w,代表树上存在一条连接 uu 和 vv 边权为 ww 的路径。
接下来 mm 行,每行一个整数 kk,代表一次询问。
输出格式
对于每次询问输出一行一个字符串代表答案,存在输出 AYE
,否则输出 NAY
。
题解:
看起来像是POI波兰那边的题。
算是点分治的模板?
关于点分治的讲解,请看:
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define N 10001
#define re register
inline int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
return x*f;
}
int n,m,query[101];
int cnt=0,mp[N],size[N],root,tot=0,d[N],b[N],a[N];
bool vis[N],ans[101];
int to[N<<1],nxt[N<<1],head[N],val[N<<1];
void add(int a,int b,int c)
{
cnt++;
nxt[cnt]=head[a];
to[cnt]=b;
val[cnt]=c;
head[a]=cnt;
}
void getroot(int x,int fa,int total)
{
size[x]=1;
mp[x]=0;
for(re int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==fa||vis[y])
continue;
getroot(y,x,total);
size[x]+=size[y];
mp[x]=max(size[y],mp[x]);
}
mp[x]=max(mp[x],total-size[x]);
if(!root||mp[x]<mp[root])
root=x;
}
bool cmp(int x,int y)
{
return d[x]<d[y];
}
void get_dis(int x,int fa,int dis,int from)
{
a[++tot]=x;
d[x]=dis;
b[x]=from;
for(re int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==fa||vis[y])
continue;
get_dis(y,x,dis+val[i],from);
}
}
void calc(int x)
{
tot=0;
a[++tot]=x;
d[x]=0;
b[x]=x;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(vis[y])
continue;
get_dis(y,x,val[i],y);
}
sort(a+1,a+tot+1,cmp);
for(int i=1;i<=m;i++)
{
int l=1,r=tot;
if(ans[i])
continue;
while(l<r)
{
if(d[a[l]]+d[a[r]]>query[i])
r--;
else if(d[a[l]]+d[a[r]]<query[i])
l++;
else if(b[a[l]]==b[a[r]])
{
if(d[a[r]]==d[a[r-1]])
r--;
else
l++;
}
else
{
ans[i]=1;
break;
}
}
}
}
void dfz(int x)
{
vis[x]=1;
calc(x);
for(re int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(vis[y])
continue;
root=0;
getroot(y,0,size[y]);
dfz(root);
}
}
int main()
{
n=read(),m=read();
for(re int i=1;i<n;i++)
{
int x,y,w;
x=read(),y=read(),w=read();
add(x,y,w);
add(y,x,w);
}
for(re int i=1;i<=m;i++)
{
query[i]=read();
if(!query[i])
ans[i]=1;
}
mp[0]=n;
getroot(1,0,n);
dfz(root);
for(re int i=1;i<=m;i++)
if(ans[i])
puts("AYE");
else
puts("NAY");
return 0;
}