luogu 3806

https://www.luogu.org/problemnew/show/P3806

点分治棵题

对于每次询问,离线处理,每次取重心点分治,查询到每个位置,对于每次询问进行查询.

#include<stdio.h>
#include<algorithm>
#include<set>
#define FOR(i,s,t) for(register int i=s;i<=t;++i)
#define ROF(i,s,t) for(register int i=s;i>=t;--i)
#define VIS(now) for(register int e=las[now];e;e=nxt[e])
using std::set;
const int N=10011,MAXX=10000011;
int heap[N],keep[N];
bool vis[N],ans[N];
int n,m,tot,k;
int nxt[N<<1],las[N],to[N<<1],q[N],sz[N],w[N<<1],dis[N<<1];
set<int>s;
int x,y,z;
inline void add(int x,int y,int z){
    nxt[++tot]=las[x];las[x]=tot;to[tot]=y;w[tot]=z;
}
inline void dfs_size(int x,int p,int &mn,int &G){
    sz[x]=1;
    int maxx=0;
    VIS(x)
        if(to[e]!=p&&!vis[to[e]]){
            dfs_size(to[e],x,mn,G);
            sz[x]+=sz[to[e]];
            if(maxx<sz[to[e]])
                maxx=sz[to[e]];
        }
    if(maxx<n-sz[x])
        maxx=n-sz[x];
    if(maxx<mn)
        mn=maxx,G=x;
}
inline int getG(int x){
    int mn=n,G=0;
    dfs_size(x,0,mn,G);
    return G;
}
inline void dfs_path(int x,int p,int len){
    if(len>k)return;
    keep[++keep[0]]=len;
    FOR(i,1,m)
        if(s.count(q[i]-len))ans[i]=1;
    VIS(x)
        if(to[e]!=p&&!vis[to[e]])
            dfs_path(to[e],x,len+w[e]);
}
inline void find(int x){
    int G=getG(x);
    s.clear();
    s.insert(0); 
    vis[G]=1;
    VIS(G)
        if(!vis[to[e]]){
            keep[0]=0;
            dfs_path(to[e],G,w[e]);
            FOR(i,1,keep[0])
                s.insert(keep[i]); 
        }
    VIS(G)
        if(!vis[to[e]])
            find(to[e]);
}
int main(){
    scanf("%d%d",&n,&m); 
    FOR(i,2,n){
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
        add(y,x,z);
    }
    FOR(i,1,m){
        scanf("%d",q+i); 
        if(q[i]>k)k=q[i];
    }
    find(1);
    FOR(i,1,m)
        ans[i]?puts("AYE"):puts("NAY");
    return 0;
}

  

posted @ 2017-11-27 15:34  Stump  阅读(127)  评论(0编辑  收藏  举报