洛谷 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\n",ans); 91 return 0; 92 }