【NOIP2016提高A组模拟8.19】(雅礼联考day2)树上路径

题目

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

分析

点分治,设当前为x的,求在以x为根的子树中,经过x的路径(包括起点或终点在x)中长度大于等于S的最小值。
假设i有3个儿子,j、k、l,
首先将以j为根的子树中的所有点到x的距离求出来,放进队列中。排个序。
接着将以k为根的子树中的所有点到x的距离求出来,一个一个点枚举,在队列中二分,求出一段大于等于S并且最小的路径,与ans比较,取小。再将它们放进队列中。排个序。
再以j为根的子树中的所有点到x的距离求出来,同样更新答案,在再加入队列。
对于起点或终点在x的,在一开始就加入队列,就可以了。
时间复杂度\(O(nlog_2^2n)\)
事实上菊花图卡不过,但还是水过了。

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
const int mo=1000000007;
const int N=100005;
using namespace std;
int dis[N],d[N],root,last[N],next[N*2],to[N*2],v[N*2],s,e,ans=maxlongint,n,m,tot,size[N],mx,ff;
bool bz[N];
int bj(int x,int y,int z)
{
    next[++tot]=last[x];
    last[x]=tot;
    to[tot]=y;
    v[tot]=z;
}
int findroot(int x,int fa)
{
    size[x]=1;
    int num=0;
    for(int i=last[x];i;i=next[i])
    {
        int j=to[i];
        if(j!=fa && bz[j])
        {
            findroot(j,x);
            size[x]+=size[j];
            num=max(num,size[j]);
        }
    }
    num=max(ff-size[x],num);
    if(num<mx)
    {
        root=x;
        mx=num;
    } 
}
int sodis(int x,int fa,int val)
{
    d[++tot]=val;
    for(int i=last[x];i;i=next[i])
    {
        int j=to[i];
        if(j!=fa && bz[j])
        {
            sodis(j,x,val+v[i]);
        }
    }
}
int rf(int l,int r,int val)
{
    while(l<r)
    {
        int mid=(l+r)/2;
        if(d[mid]+val<s)
            l=mid+1;
        else
            r=mid;
    }
    if(d[l]+val>=s)
        ans=min(d[l]+val,ans);
    else
    if(d[r]+val>=s)
        ans=min(d[r]+val,ans);
}
int dg(int x,int fa)
{
    bz[x]=false;
    tot=1;
    d[1]=0;
    for(int i=last[x];i;i=next[i])
    {
        int j=to[i];
        if(j!=fa && bz[j])
        {
            int k=tot+1;
            sodis(j,x,v[i]);
            for(int l=k;l<=tot;l++)
            {
                rf(1,k-1,d[l]);
            }
            sort(d+1,d+1+tot);
        }
    }
    int f=tot;
    for(int i=last[x];i;i=next[i])
    {
        int j=to[i];
        if(j!=fa && bz[j])
        {
            ff=f-1;
            root=0;
            mx=maxlongint;
            findroot(j,x);
            dg(root,x);
        }
    }
}
int main()
{
    scanf("%d%d%d",&n,&s,&e);
    for(int i=1;i<=n-1;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        bj(x,y,z);
        bj(y,x,z);
    }
    memset(bz,true,sizeof(bz));
    root=0;
    ff=n;
    mx=maxlongint;
    findroot(1,0);
    dg(root,0);
    if(ans>e)
        printf("-1\n");
    else
        printf("%d\n",ans);
}

猜你喜欢

转载自www.cnblogs.com/chen1352/p/9045313.html
今日推荐