【JZOJ 4715】树上路径

Description

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

Solution

很显然的点分治嘛,
为了防止选的点在同一棵子树中,我们再维护一个数组表示当前位置往后的第一个和我不在一块子树的点的位置,
我们先象标准点分治一样维护两个指针i,j,在维护完j以后,判断当前的j是否和i在一颗子树中,是就跳到往后第一个不是的,再算答案,
复杂度: O(nlog2(n)) (也敢开 105 ??!!)

Code

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
using namespace std;
const int N=100500,maxlongint=2147483640;
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,ans,S,E;
int a[N],b0;
struct qqww
{int s,g,nx;}b[N];
bool z[N];
int H[N],CE,CE1;
int A[N],B[2*N][3],B0;
int min(int q,int w){return q<w?q:w;}
int max(int q,int w){return q>w?q:w;}
void link(int q,int w,int e)
{
    B[++B0][0]=A[q],A[q]=B0,B[B0][1]=w,B[B0][2]=e;
    B[++B0][0]=A[w],A[w]=B0,B[B0][1]=q,B[B0][2]=e;
}
int findc(int q,int fa,int w)
{
    H[q]=1;int t=0,t1;
    efo(i,q)if(B[i][1]!=fa&&!z[B[i][1]])t1=findc(B[i][1],q,w),H[q]+=t1,t=max(t,t1);
    if(max(w-H[CE],CE1)>max(w-H[q],t))CE=q,CE1=t;
    return H[q];
}
void dfs1(int q,int e,int fa,int g)
{
    b[++b0].s=e;b[b0].g=g;
    efo(i,q)if(B[i][1]!=fa&&!z[B[i][1]])dfs1(B[i][1],e+B[i][2],q,g);
}
bool PX(qqww q,qqww w){return q.s<w.s||(q.s==w.s&&q.g<w.g);}
void divide(int q,int ALLN)
{
    CE=CE1=0;findc(q,q,ALLN);
    q=CE;z[q]=1;
    b0=0;
    efo(i,q)if(!z[B[i][1]])dfs1(B[i][1],B[i][2],q,B[i][1]);
    sort(b+1,b+1+b0,PX);
    int t=b0+1;
    fod(i,b0,1)
    {
        b[i].nx=t;
        if(b[i].g!=b[i-1].g)t=i;
        if(b[i].s>=S)ans=min(ans,b[i].s);
    }
    int j=b0;
    fo(i,1,b0)
    {
        while(b[i].s+b[j-1].s>=S)j--;
        t=j;if(b[t].g==b[i].g)t=b[t].nx;
        if(b[i].s+b[t].s>=S&&t<=b0)ans=min(ans,b[i].s+b[t].s);
    }
    efo(i,q)if(!z[B[i][1]])divide(B[i][1],H[B[i][1]]);
}
int main()
{
    int q,w,e;
    read(n),read(S),read(E);
    ans=maxlongint;;
    fo(i,1,n-1)read(q),read(w),read(e),link(q,w,e);
    ans=maxlongint;
    divide(1,n);
    if(ans<=E)printf("%d\n",ans);
        else printf("-1\n");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值