求助求助,7,9被卡,但时间复杂度应该没问题。 如果有能帮忙看看的朋友,提前感谢!
#include<bits/stdc++.h>
using namespace std;
#define int long long
int k;
int h[40010],e[40010],ne[40010],w[40010],idx;
int use[20010];
int d[20010];
int f[20010],siz[20010];
int cnt,Siz,rt;
void add(const int &a,const int &b,const int &c)
{
w[idx]=c,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
w[idx]=c,e[idx]=a,ne[idx]=h[b],h[b]=idx++;
}
//求重心
void getroot(const int &x,const int &fa)//x为当前点,fa为父亲节点
{
f[x]=0,siz[x]=1;//f表示这个点最大子树的大小,siz是这个点子树大小的和
for(int i=h[x];i!=-1;i=ne[i])//枚举儿子
{
int y=e[i];
if(use[y]||y==fa) continue;//use表示之前遍历过了,这里没啥用
getroot(y,x);//往下遍历
f[x]=max(f[x],siz[y]);//更新f
siz[x]+=siz[y];
}
f[x]=max(f[x],Siz-siz[x]);//Siz表示在现在这棵子树中点的总数,开始时Siz=n,除了枚举的儿子所在的子树外,还有一棵子树是上面的那一堆,容斥原理
if(f[x]<f[rt]) rt=x;//更新root
}
//求到重心的距离
int findunder(int l,const int &x)//找下界,r左移
{
int ans=0,r=cnt;
while(l<=r)
{
int mid(l+r>>1);
if(d[mid]<x) l=mid+1;
else ans=mid,r=mid-1;
}
return ans;
}
int findup(int l,const int &x)//找上界
{
int ans=0,r=cnt;
while(l<=r)
{
int mid(l+r>>1);
if(d[mid]<=x) ans=mid,l=mid+1;
else r=mid-1;
}
return ans;
}
void getd(const int &x,const int &fa,const int &dis)
{
for(int i=h[x];i!=-1;i=ne[i])
{
int j=e[i];
if(use[j]||j==fa) continue;
d[++cnt]=dis+w[i];
getd(j,x,d[cnt]);
}
}
//求答案
int getans(const int &x,const int &dis,const int&k)
{
d[cnt=1]=dis;
getd(x,0,dis);
sort(d+1,d+1+cnt);
int l=1,ans=0;
while(l<cnt&&d[l]+d[cnt]<k) l++;
while(l<cnt&&d[l]<=k-d[l])//保证要找的在后面
{
int d1=findunder(l,k-d[l]),d2=findup(l,k-d[l]);//也可以用lower_bound()和upper_bound()实现
if(d2>=d1)ans += d2-d1+1;//ans表示符合要求的
l++;
}
return ans;
}
int ans=0;//以x点为重心的树产生的符合k的答案
//分治划分
void fz(const int &x,int k)//x就是树根
{
//cout<<"x:"<<x<<endl;
use[x]=1;
ans += getans(x,0,k);//
//printf("x=%d,ans1=%d\n",x,ans);
for(int i=h[x];i!=-1;i=ne[i])
{
int j=e[i];
if(use[j]) continue;
int dis=w[i];
ans -= getans(j,dis,k);
// printf("x=%d,ans2=%d\n",x,ans);
Siz=siz[j],rt=0;
getroot(j,x);//找子树中的重心
// printf("%d kid-ans %d",x,rt);
// rts[j]=rt;
fz(rt,k);
}
}
signed main()
{
f[0]=1e9+7;
memset(h,-1,sizeof h);
int n,m;
scanf("%lld%lld",&n,&m);
for(int i=0;i<n-1;i++)
{
int a,b,c;
scanf("%lld%lld%lld",&a,&b,&c);
add(a,b,c);
}
/*for(int i=1;i<=n;i++)
{
printf("%d:",i);
for(int j=h[i];j!=-1;j=ne[j]) printf("%d ",e[j]);
printf("\n");
}*/
Siz=n;
getroot(1,1);
//for(int i=1;i<=n;i++) cout<<i<<" f:"<<f[i]<<" siz:"<<siz[i]<<endl;
//cout<<"rt:"<<rt<<endl;
int root=rt;
int q[100];
for(int i=0;i<m;i++)
{
scanf("%lld",&q[i]);
//memset(use,0,sizeof use);
}
for(int i=0;i<m;i++)
{
ans=0;
for(int i=0;i<=n;i++)use[i]=0;
fz(root,q[i]);
if(ans) printf("AYE\n");
else printf("NAY\n");
}
}