http://www.elijahqi.win/2018/01/20/bzoj3219/
Description
Tar国正在准备每年一次的巡游活动。国王将会在一个城市S里召集人群,沿着城市间的道路进行游览,最终在一个城市T里发表他每年一次的著名演讲。
Tar国有N个城市,由于国家的特殊要求,每两个城市之间存在一条唯一的简单通路。
国王希望借着这个机会视察Tar国的城市建设,因此他提出S到T的距离不能少于L条道路。
同时,国王的私人医生检查了他的身体情况后,断定国王的身体不适合做长途旅行,因此他要求S到T的距离不能多于R条道路。
另外,政府希望跟随国王的人民沿途不仅能看到城市风景,还能看到城市外的美丽乡村。因此每条道路定义了一个魅力值Ci,一条路径的魅力值定义为这条路径的中位数。更详细的说法是这样的:
将路径上所有边的魅力值排序,得到序列{Ai}。假设i=2k+c(0<=c<=1),中位数就是A(k+1)。
你的任务就是求出魅力值最大的路径,并输出这个魅力值。
Input
第一行是三个整数N,L,R,表示Tar国的城市个数、路径的最小和最大长度。
接下来N-1行,每行3个整数Ai,Bi,Ci,表示有一条连接Ai和Bi且魅力值Ci的道路。
Output
仅一行,表示最大的魅力值。如果不存在这样的路径,输出-1。
Sample Input
5 1 4
1 2 1
1 3 4
3 4 7
3 5 2
Sample Output
7
HINT
对于100%的数据:N<=100000,1<=L<=R<=N-1,1<=Ci<=1000000000。
Source
树的分治
基本同http://blog.youkuaiyun.com/elijahqi/article/details/79094248
注意我每次二分答案之后把大于等于答案的数改成1反之改成-1 如果做到>=0的数我就退出即可 最后验证答案 如果>=0 l=mid+1;else r=mid-1
#include<deque>
#include<cstdio>
#include<algorithm>
#define N 110000
#define inf 0x3f3f3f3f
using namespace std;
inline char gc(){
static char now[1<<16],*S,*T;
if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0;char ch=gc();
while(ch<'0'||ch>'9') ch=gc();
while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
return x;
}
struct node{
int y,z,next;
}data[N<<1];
struct node1{
int y,size,z;
}qq[N];
int n,L,R,h[N],num,size[N],ff[N],sum,root,dep[N],max1,ans;bool visit[N];
int f[N],g[N],dis[N];
inline void get_root(int x,int fa){
size[x]=1;ff[x]=0;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y;if (visit[y]||y==fa) continue;
get_root(y,x);size[x]+=size[y];ff[x]=max(ff[x],size[y]);
}ff[x]=max(ff[x],sum-size[x]);
if (ff[root]>ff[x]) root=x;
}
inline bool cmp(node1 a,node1 b){return a.size<b.size;}
inline void dfs(int x,int fa,int mid){
max1=max(max1,dep[x]);f[dep[x]]=max(dis[x],f[dep[x]]);
for (int i=h[x];i;i=data[i].next){
int y=data[i].y,z=data[i].z;if (y==fa||visit[y]) continue;
dis[y]=dis[x]+(z>=mid?1:-1);dep[y]=dep[x]+1;dfs(y,x,mid);
}
}
inline int check(int x,int mid){
dep[x]=dis[x]=0;int max_deep=0;int flag=-1;
for (int i=1;i<=num;++i){
int y=qq[i].y,z=qq[i].z;max1=0;deque<int>q;f[0]=0;g[0]=0;
dis[y]=dis[x]+(z>=mid?1:-1);dep[y]=dep[x]+1;dfs(y,x,mid);max_deep=max(max_deep,max1);
for (int j=max_deep;j>=L;--j) {
while(!q.empty()&&g[j]>g[q.back()]) q.pop_back();q.push_back(j);}
for (int j=0;j<=max1;++j){
while(!q.empty()&&j+q.front()>R) q.pop_front();
if (!q.empty()) if (f[j]+g[q.front()]>=0) {flag=f[j]+g[q.front()];break;}
while(!q.empty()&&L-j-1>=0&&g[L-j-1]>g[q.back()]) q.pop_back();q.push_back(L-j-1);
}
for (int j=0;j<=max1;++j) g[j]=max(g[j],f[j]),f[j]=-inf;
if (flag>=0) break;
}
for (int i=0;i<=max_deep;++i) g[i]=-inf;return flag;
}
inline void solve(int x){
if (sum<L) return;visit[x]=1;num=0;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y,z=data[i].z;
if (size[y]>size[x]) size[y]=sum-size[x];
qq[++num].size=size[y];qq[num].y=y;qq[num].z=z;
}sort(qq+1,qq+num+1,cmp);int l=ans,r=1e9;
while(l<=r){
int mid=l+r>>1;
if (check(x,mid)>=0) l=mid+1;else r=mid-1;
}ans=max(r,ans);
for (int i=h[x];i;i=data[i].next){
int y=data[i].y;if (visit[y]) continue;
root=0;sum=size[y];get_root(y,x);solve(root);
}
}
int main(){
freopen("bzoj3219.in","r",stdin);
n=read();L=read();R=read();
for (int i=0;i<=n;++i) f[i]=g[i]=-inf;
for (int i=1;i<n;++i){
int x=read(),y=read(),z=read();
data[++num].y=y;data[num].z=z;data[num].next=h[x];h[x]=num;
data[++num].y=x;data[num].z=z;data[num].next=h[y];h[y]=num;
}sum=n;ff[0]=inf;root=0;get_root(1,0);
solve(root);printf("%d",ans);
return 0;
}