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;
}