BZOJ 1316: 树上的询问【点分治】

1316: 树上的询问

【题目描述】
传送门

【题解】

点分治,然后对于每个询问用二分查找就可以了。
我尽然以9979ms卡过去了。

【代码如下】

#include<cstdio>
#include<algorithm>
#define MAXN 10005
using namespace std;
int n,m,Rot,RotSize,Q[105];
int Siz[MAXN],Maxs[MAXN],Ans[105],dst[MAXN],Al[MAXN],Altop;
bool vis[MAXN];
struct Edge{
    int tot,lnk[MAXN],nxt[MAXN<<1],son[MAXN<<1],W[MAXN<<1];
    void Add(int x,int y,int z){son[++tot]=y;W[tot]=z;nxt[tot]=lnk[x];lnk[x]=tot;}
}E;
void Get_Rot(int x,int fa){
    Siz[x]=1;Maxs[x]=0;
    for(int j=E.lnk[x];j;j=E.nxt[j])
    if(!vis[E.son[j]]&&E.son[j]!=fa){
        Get_Rot(E.son[j],x);Siz[x]+=Siz[E.son[j]];
        Maxs[x]=max(Maxs[x],Siz[E.son[j]]);
    }
    Maxs[x]=max(Maxs[x],RotSize-Siz[x]);
    if(Maxs[x]<Maxs[Rot]) Rot=x;
}
void Get_Dst(int x,int fa){
    Siz[x]=1;Al[++Altop]=dst[x];
    for(int j=E.lnk[x];j;j=E.nxt[j])
    if(!vis[E.son[j]]&&E.son[j]!=fa){
        dst[E.son[j]]=dst[x]+E.W[j];
        Get_Dst(E.son[j],x);
        Siz[x]+=Siz[E.son[j]];
    }
}
int Fnd_left(int x,int L,int R){
    int P=0;
    for(int mid=(R+L)>>1;L<=R;mid=(R+L)>>1){
        if(Al[mid]==x) R=mid-1,P=mid;
        if(Al[mid]<x) L=mid+1;else R=mid-1;
    }
    return P;
}
int Fnd_right(int x,int L,int R){
    int P=-1;
    for(int mid=(R+L)>>1;L<=R;mid=(R+L)>>1){
        if(Al[mid]==x) L=mid+1,P=mid;
        if(Al[mid]<x) L=mid+1;else R=mid-1;
    }
    return P;
}
int Cal(int x,int y,int k){
    Altop=0;dst[x]=y;Get_Dst(x,0);
    sort(Al+1,Al+1+Altop);
    int L=1,R=Altop,Now=0;
    for(int i=1;i<=Altop;i++)
    if(Al[i]+Al[i]<=Q[k])
    Now+=Fnd_right(Q[k]-Al[i],L,R)-Fnd_left(Q[k]-Al[i],L,R)+1;
    else break;
    return Now;
}
void Solve(int x){
    for(int i=1;i<=m;i++) Ans[i]+=Cal(x,0,i);vis[x]=1;
    for(int j=E.lnk[x];j;j=E.nxt[j])
    if(!vis[E.son[j]]){
        for(int i=1;i<=m;i++) Ans[i]-=Cal(E.son[j],E.W[j],i);
        Maxs[0]=RotSize=Siz[E.son[j]];Rot=0;
        Get_Rot(E.son[j],0);Solve(Rot);
    }
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("prob.in","r",stdin);
    freopen("prob.out","w",stdout);
    #endif
    scanf("%d%d",&n,&m);
    for(int i=1;i<n;i++){
        int x,y,z;scanf("%d%d%d",&x,&y,&z);
        E.Add(x,y,z);E.Add(y,x,z);
    }
    for(int i=1;i<=m;i++) scanf("%d",&Q[i]);
    Maxs[0]=RotSize=n;Rot=0;Get_Rot(1,0);Solve(Rot);
    for(int i=1;i<=m;i++) printf(Ans[i]>0?"Yes\n":"No\n");
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_41357771/article/details/80869773