洛谷 P2680 运输计划(二分答案+树上差分)

题目链接:https://www.luogu.com.cn/problem/P2680

首先是最小值最大的问题,可以考虑二分答案。

 首先用LCA预处理出u,v两点之间的距离,并记录最大距离。然后二分最小距离,如果u,v两点之间的距离小于二分的x,那么无需管它,否则进行树上差分,并且cnt++。如果cnt==0,直接可行;否则,对差分数组进行前缀和求每条边经过的次数。记录经过cnt次的边的边权最大值,如果u、v两点间的最大值减去边权最大值仍大于二分的x,那么不行。

AC代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int N=300005;
 7 struct node{
 8     int to,next,w;
 9 }edge[N<<1];
10 struct Node{
11     int u,v,lca,sum;
12 }q[N];
13 int head[N],tot,cnt,maxx,m,n,maxh;
14 int dep[N],f[N][30],e[N],dis[N],sa[N];
15 void init(){
16     memset(head,-1,sizeof(head));
17 }
18 void add(int u,int v,int w){
19     edge[tot].next=head[u];
20     edge[tot].to=v;
21     edge[tot].w=w;
22     head[u]=tot++;
23 }
24 void DFS(int u,int fa){
25     dep[u]=dep[fa]+1;
26     f[u][0]=fa;
27     for(int i=1;(1<<i)<=dep[u];i++) f[u][i]=f[f[u][i-1]][i-1];
28     for(int i=head[u];i!=-1;i=edge[i].next){
29         int v=edge[i].to;
30         if(v==fa) continue;
31         dis[v]=dis[u]+edge[i].w;
32         e[v]=edge[i].w;
33         DFS(v,u);
34     }
35 }
36 int lca(int u,int v){
37     if(dep[u]<dep[v]) swap(u,v);
38     for(int i=20;i>=0;i--) if(dep[f[u][i]]>=dep[v]) u=f[u][i];
39     if(u==v) return u;
40     for(int i=20;i>=0;i--) if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
41     return f[u][0];
42 }
43 void get_sum(int u,int fa){
44     for(int i=head[u];i!=-1;i=edge[i].next){
45         int v=edge[i].to;
46         if(v==fa) continue;
47         get_sum(v,u);
48         sa[u]+=sa[v];
49     }
50     if(sa[u]==cnt) maxx=max(maxx,e[u]);
51 }
52 int judge(int x){
53     memset(sa,0,sizeof(sa));
54     cnt=0;
55     maxx=0;
56     for(int i=1;i<=m;i++){
57         if(q[i].sum<=x) continue;
58         sa[q[i].u]++; sa[q[i].v]++;
59         sa[q[i].lca]-=2;
60         cnt++;
61     }
62     get_sum(1,0);
63     if(cnt==0) return 1;
64     if(maxh-maxx>x) return 0;
65     return 1;
66 }
67 int main(){
68     init();
69     scanf("%d%d",&n,&m);
70     for(int i=1;i<n;i++){
71         int u,v,w;
72         scanf("%d%d%d",&u,&v,&w);
73         add(u,v,w); add(v,u,w);
74     }
75     DFS(1,0);
76     for(int i=1;i<=m;i++){
77         int u,v;
78         scanf("%d%d",&u,&v);
79         q[i].lca=lca(u,v);
80         q[i].u=u; q[i].v=v;
81         q[i].sum=dis[u]+dis[v]-2*dis[q[i].lca];
82         maxh=max(maxh,q[i].sum);
83     }
84     int l=0,r=maxh,ans=0;
85     while(l<=r){
86         int mid=(l+r)>>1;
87         if(judge(mid)) ans=mid,r=mid-1;
88         else l=mid+1;
89     }
90     printf("%d
",ans);
91     return 0;
92 }
AC代码