树上路径

来源:互联网 发布:pg数据库substring 编辑:程序博客网 时间:2024/04/25 21:34

题目描述

给出一棵树,求出最小的k,使得,且在树中存在路径p,使得k>=S且k<=E。(k为路径p上的边的权值和)
n<=10^5,|E-S|<=10^6,1<=Wi<=1000,|E|,|S|<=10^9

怎么看都是点剖。

而对k有两个限制,不能直接求最小值,但是可以求在这个区间范围内的k有多少个。

二分+点剖

二分E的值,求在这个区间范围内的k的数量,若>0则合法。
只有第一次点剖才排序,然后保存排序后的数值,这样复杂度为O(nlog2n),否则复杂度是O(nlog3n)

代码

#include<cstring>#include<algorithm>#include<cstdio>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)#define ll long longusing namespace std;const int maxn=100000+100;int i,j,n,d[maxn],f[maxn],s[maxn],root,mid,ss,l,r,t,ro[maxn];ll ans;int q[maxn*50],st[maxn*50],en[maxn*50],tt;int k[maxn],g[maxn*2],next[maxn*2],c[maxn*2],num,cnt;int k1[maxn],g1[maxn*2],next1[maxn*2],b;bool bz[maxn];void add(int x,int y,int z){next[++num]=k[x];k[x]=num;g[num]=y;c[num]=z;}void add1(int x,int y){next1[++cnt]=k1[x];k1[x]=cnt;g1[cnt]=y;}void dfs(int x,int y){    s[x]=1,f[x]=0;    int i=k[x];    while (i){        if ((!bz[g[i]])&&(g[i]!=y)) dfs(g[i],x),s[x]+=s[g[i]],f[x]=max(f[x],s[g[i]]);        i=next[i];    }    f[x]=max(f[x],f[0]-s[x]);if (f[x]<f[root]) root=x;}void df(int x,int y){    if (d[x]>mid) return;    q[++num]=d[x];    int i=k[x];    while (i){        if ((!bz[g[i]])&&(g[i]!=y)) d[g[i]]=d[x]+c[i],df(g[i],x);        i=next[i];    }}ll chu(int x){    tt++;    if (st[tt]==0) {        st[tt]=num+1,df(x,0),en[tt]=num;        sort(q+st[tt],q+1+en[tt]);    }    int i,j1=en[tt],j=en[tt];ll w=0;    fo(i,st[tt],en[tt]-1){        while (q[i]+q[j]>mid&&j>=i) j--;if (j<=i) break;        if (j1==i) j1=i+1;else        while ((q[i]+q[j1-1]>=ss)&&(j1-1>i)) j1--;        if ((q[i]+q[j1]<ss)||(j<j1)) continue;        w+=j-j1+1;    }    return w;}void fen(int x){    bz[x]=1,d[x]=0,b=0,ans+=chu(x);b=1;    int i=k[x];    while (i){        if (!bz[g[i]]) add1(x,g[i]),ans-=chu(g[i]);        i=next[i];    }i=k1[x];    while (i){        int go=g1[i];        f[root=0]=s[go],dfs(go,0),ro[++t]=root;        fen(ro[t]);        i=next1[i];    }}void fen1(int x){    if (ans) return;    b=0,ans+=chu(x);    int i=k1[x];b=1;    while (i) {        ans-=chu(g1[i]);        i=next1[i];    }    i=k1[x];while (i)fen1(ro[++t]),i=next1[i];}int main(){    scanf("%d%d%d",&n,&ss,&r);l=ss,mid=r;    fo(i,1,n-1) {int x,y,z;scanf("%d%d%d",&x,&y,&z);add(x,y,z);add(y,x,z);}    t=0;f[root=0]=n;    dfs(1,0);ro[t]=root;num=tt=0;    fen(root);    if (ans==0) {printf("-1\n");return 0;}    while (l<r){        mid=(l+r)/2,t=tt=ans=0,fen1(ro[t]);        if (ans) r=mid;else l=mid+1;    }    printf("%d\n",l);}
0 0
原创粉丝点击