【JZOJ4715】树上路径

Description

给出一棵树,求出最小的k,使得,且在树中存在路径p,使得k>=S且k<=E。(k为路径p上的边的权值和)

题目描述使人神清气爽。——LYD729

Solution

树上多条路径问题显然用点分治解决。

于是像常规点分治那样,求出每个点到重心的距离,排序。然后枚举开头,二分出一个位置使得距离大于等于下界,然后如果这两个点在同一棵子树就把二分出的点跳到另一棵子树上。

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 100001
#define M 200001
using namespace std;
int p,q;
int to[M],next[M],last[M],num=0;
int val[M];
int siz[N];
int dis[N];
int fa[N];
int f[N];
bool vis[N];
struct node{
    int x,f;
}d[N];
int tot;
void link(int x,int y,int c)
{
    num++;
    to[num]=y;
    next[num]=last[x];
    last[x]=num;
    val[num]=c;
}
bool cmp(node x,node y)
{
    return x.x<y.x;
}
int rt;
int cnt=0;
void get(int x,int t,int from)
{
    for(int i=last[x];i;i=next[i])
    {
        int v=to[i];
        if(v!=t && !vis[v])
        {
            dis[v]=dis[x]+val[i];
            get(v,x,from);
        }
    }
    if(dis[x])
    {
        tot++;
        d[tot].x=dis[x];
        d[tot].f=from;
    }
}
void find(int x,int p,int t)
{
    siz[x]=1;
    f[x]=0;
    for(int i=last[x];i;i=next[i])
    {
        int v=to[i];
        if(v!=t && !vis[v])
        {
            find(v,p,x);
            siz[x]+=siz[v];
            f[x]=max(f[x],siz[v]);
        }
    }
    f[x]=max(f[x],p-siz[x]);
    if(f[x]<f[rt]) rt=x;
}
int ans=2147483647;
int nx[N];
void calc()
{
    sort(d+1,d+tot+1,cmp);
    nx[tot]=tot+1;
    fd(i,tot-1,1)
    if(d[i].f==d[i+1].f) nx[i]=nx[i+1];
    else nx[i]=i+1;
    if(tot==1 && d[1].x>=p && d[1].x<=q && d[1].x<ans) ans=d[1].x; 
    fo(i,1,tot-1)
    {
        if(d[i].x>=p && d[i].x<ans) ans=d[i].x;
        int l=i+1,r=tot;
        while(l+1<r)
        {
            int mid=(l+r)/2;
            if(d[i].x+d[mid].x>=p) r=mid;
            else l=mid;
        }
        int t=l;
        if(d[i].x+d[t].x<p) t++;
        while(d[i].f==d[t].f) t=nx[t];
        if(t>tot) continue;
        if(d[i].x+d[t].x>=p && d[i].x+d[t].x<=q)
        {
            if(ans>d[i].x+d[t].x) ans=d[i].x+d[t].x;
        }
    }
}
void dfs(int x,int t)
{
    vis[x]=true;
    tot=0;
    dis[x]=0;
    for(int i=last[x];i;i=next[i])
    {
        int v=to[i];
        if(v!=t && !vis[v])
        {
            dis[v]=val[i];
            get(v,x,v);
        }
    }
    calc();
    for(int i=last[x];i;i=next[i])
    {
        int v=to[i];
        if(!vis[v] && v!=t)
        {
            rt=0;
            find(v,siz[v],x);
            dfs(rt,x);
        }
    }
}
int main()
{
    int n;
    cin>>n>>p>>q;
    fo(i,1,n-1)
    {
        int x,y,c;
        scanf("%d %d %d",&x,&y,&c);
        link(x,y,c);
        link(y,x,c);
    }
    rt=0;
    f[0]=2147483647;
    find(1,n,0);
    dfs(rt,0);
    if(ans>q) cout<<-1;
    else cout<<ans;
}
posted @ 2016-08-19 16:44  sadstone  阅读(31)  评论(0编辑  收藏  举报