传送门:洛谷-【模板】点分治1
题意
给定一棵有n个点的树
询问树上距离为k的点对是否存在。
数据范围
对于30%的数据n<=100
对于60%的数据n<=1000,m<=50
对于100%的数据n<=10000,m<=100,c<=1000,K<=10000000
题解
此题贴板可A。
(题解越来越水了)
代码
#include<bits/stdc++.h>
using namespace std;
const int INF=0x7fffffff;
const int N=1e4+10;
const int K=1e7+10;
typedef long long ll;
int n,x,y,m,MX,tot,root,S,cnt;
int sim[N],head[N],to[N<<1],nxt[N<<1];
ll w[N<<1],c;
ll k,sum[N],mx[N],exi[K],dis[N];
bool vis[N];
inline void lk(int u,int v,ll val)
{
to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=val;
}
inline void getroot(int now,int f)
{
sim[now]=1;mx[now]=0;
for(int i=head[now];i;i=nxt[i]){
int e=to[i];
if(vis[e]||(e==f)) continue;
getroot(e,now);
sim[now]+=sim[e];
if(sim[e]>mx[now]) mx[now]=sim[e];
}
mx[now]=max(mx[now],(ll)S-sim[now]);
if(mx[now]<MX){MX=mx[now];root=now;}
}
inline void query(int now,int f,ll val)
{
dis[++cnt]=val;
for(int i=head[now];i;i=nxt[i]){
int e=to[i];
if(vis[e]||(e==f)) continue;
query(e,now,val+w[i]);
}
}
inline void solve(int now)
{
cnt=0;
query(now,0,0);
for(int i=1;i<cnt;i++){
for(int j=i+1;j<=cnt;j++){
exi[dis[i]+dis[j]]++;
}
}
}
inline void sol(int now,ll val)
{
cnt=0;
query(now,0,val);
for(int i=1;i<cnt;i++){
for(int j=i+1;j<=cnt;j++){
exi[dis[i]+dis[j]]--;
}
}
}
inline void divide(int now)
{
vis[now]=true;solve(now);
for(int i=head[now];i;i=nxt[i]){
int e=to[i];
if(vis[e]) continue;
sol(e,w[i]);
S=sim[e];MX=INF;root=0;
getroot(e,0);
divide(root);
}
}
int main(){
memset(vis,false,sizeof(vis));
exi[0]=true;
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++){
scanf("%d%d%lld",&x,&y,&c);
lk(x,y,c);lk(y,x,c);
}
S=n;MX=INF;
getroot(1,0);
divide(root);
while(m--){
scanf("%d",&k);
if(exi[k]){
printf("AYE\n");
}else{
printf("NAY\n");
}
}
return 0;
}