【NOIP2017提高组模拟7.3】B

树上路径统计,点分治解决。

统计一段区间,naive地用了set解决,这样的复杂度是O(nlog^2n)的

考场代码出了个问题,统计答案时找到了之前的最优答案,但是没有加上新的一段,导致60分

#include<iostream>
#include<cstdio>
#include<set>

using namespace std;

inline int rd(){
    int ret=0,f=1;char c;
    while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    return ret*f;
}

const int MAXN = 100005;

struct Edge{
    int next,to,w;
}e[MAXN<<1];
int ecnt,head[MAXN];
inline void add(int x,int y,int w){
    e[++ecnt].next = head[x];
    e[ecnt].to = y;
    e[ecnt].w = w;
    head[x] = ecnt;
}

int n,L,R;

bool vis[MAXN];
int siz[MAXN];
void getsiz(int x,int pre){
    siz[x]=1;
    for(int i=head[x];i;i=e[i].next){
        int v=e[i].to;
        if(v==pre||vis[v]) continue;
        getsiz(v,x);
        siz[x]+=siz[v];
    }
}
int mn,root;
void getroot(int x,int pre,int tot){
    int mx=0;
    for(int i=head[x];i;i=e[i].next){
        int v=e[i].to;
        if(v==pre||vis[v]) continue;
        mx=max(mx,siz[v]);
        getroot(v,x,tot);
    }
    mx=max(mx,tot-siz[x]);
    if(mx<mn) root=x,mn=mx;
}
set<int> se;
int s[MAXN];

void dfs(int x,int pre,int dis){
    if(dis>R) return;//
    s[++s[0]]=dis;
    for(int i=head[x];i;i=e[i].next){
        int v=e[i].to;
        if(v==pre||vis[v]) continue;
        dfs(v,x,dis+e[i].w);
    }
}

int ans=1<<30;

void dac(int x){
    mn=n;
    getsiz(x,-1);
    getroot(x,-1,siz[x]);
    int u=root;vis[u]=1;
    se.clear();
    se.insert(1<<30); 
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(vis[v]) continue;
        s[0]=0;dfs(v,u,e[i].w);
        for(int j=s[0];j>=1;j--){
            int tmp=*se.lower_bound(L-s[j]);
            tmp+=s[j];
            if(tmp<ans&&tmp<=R&&tmp>=L) ans=tmp;
        }
        for(int j=s[0];j>=1;j--){
            if(s[j]<ans&&s[j]<=R&&s[j]>=L) ans=s[j];
            se.insert(s[j]);
        }
    }
    
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(!vis[v]) dac(v);
    }
}
            

int main(){
    n=rd();L=rd();R=rd();
    int x,y,w;
    for(int i=1;i<=n-1;i++){
        x=rd();y=rd();w=rd();
        add(x,y,w);add(y,x,w);
    }
    dac(1);
    if(ans==1<<30) cout<<-1;
    else cout<<ans;
    return 0;
}

 

posted @ 2018-08-15 19:44  GhostCai  阅读(123)  评论(0编辑  收藏  举报