这居然是联赛题我一脸懵逼。。根本没往那方向上想。
题目大意:
让你求树上最短的路径,但是路径长度必须>=l,<=r,n<=10^5,r-l<=10^6,l,r<=10^9;
其实是我点分治没怎么打过,这其实是一道很一眼的点分治的题。。我是懵比了。。
可以算是模板题吧,我是直接点分治莽一波,然后就过了,题解还说是二分,我比赛时候就想到是二分。。mdzz。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
#define ll long long
int n,m,i,j,k,x,y,z,tot=0,num=0;
int next[200000],head[200000],go[200000],maxv[200000],size[200000];
ll ans,len[200000],h[200000],h1[200000],L,R;
inline void add(int x,int y,int z)
{
go[++tot]=y;
len[tot]=z;
next[tot]=head[x];
head[x]=tot;
}
inline void dfssize(int x,int y)
{
int i;
size[x]++;
for (i=head[x];i;i=next[i])
if (go[i]!=y)
{
int v=go[i];
dfssize(v,x);
size[x]+=size[v];
maxv[x]=max(maxv[x],size[v]);
}
maxv[x]=max(maxv[x],n-size[x]);
}
inline void qsort(int l,int r,int mid)
{
int i,j,t,k;
for (i=l;i<=r;i++)
h1[i]=h[i];
i=l;
j=mid+1;
t=l-1;
while (i<=mid&&j<=r)
if (h1[i]<h1[j]) h[++t]=h1[i++];
else h[++t]=h1[j++];
while (i<=mid) h[++t]=h1[i++];
while (j<=r) h[++t]=h1[j++];
}
inline void dfs(int x,int y)
{
h[++num]=0;
int i,j,k=num+1,v,l;
for (v=head[x];v;v=next[v])
if (go[v]!=y)
{
//int s=go[v];
l=num+1;
dfs(go[v],x);
for (j=l;j<=num;j++)
{
h[j]+=len[v];
if (h[j]>=L) ans=min(ans,h[j]);
if (h[j]>R)
{
num=j-1;
break;
}
}
j=num;
if (j<l) continue;
for (i=k;i<l;i++)
{
while (h[i]+h[j]>=L&&j>l) j--;
if (h[i]+h[j]<L&&j<num) j++;
if (h[i]+h[j]>=L) ans=min(ans,h[i]+h[j]);
if (j==l&&h[i]+h[j]>=L) break;
}
if (k<l) qsort(k,num,l-1);
}
}
int main()
{
scanf("%d%d%d",&n,&L,&R);
for (i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
dfssize(1,0);
ans=R+1;
for (i=1;i<=n;i++)
if (maxv[i]<=n/2)
{
dfs(i,0);
break;
}
if (ans==R+1) printf("%d\n",-1);
else
printf("%lld\n",ans);
}