1. 程式人生 > >LOJ2425 NOIP2015 運輸計劃 【二分+LCA+樹上差分】*

LOJ2425 NOIP2015 運輸計劃 【二分+LCA+樹上差分】*

LOJ2425 NOIP2015 運輸計劃

LINK

題意:給你一顆樹,可以將任意一條邊的權值變成0,然後求m條路徑的長度的最小值

思路: 先二分最後的距離ans,然後我們把路程大於ans的所有路徑拿出來 然後把這些路徑的交求出來,用樹上差分的方法 然後對這個交(用點集轉化成邊集,就是每個點的上一條邊)取一個最大值 然後判斷這些邊減去這個最大值之後會不會小於等於ans

#include<bits/stdc++.h>
using namespace std;
#define fu(a,b,c) for(int a=b;a<=c;++a)
#define fd(a,b,c) for(int a=b;a>=c;--a)
int read(){ int ans=0,w=1;char c=getchar(); while(!isdigit(c)&&c!='-')c=getchar(); if(c=='-')w=-1,c=getchar(); while(isdigit(c))ans=(ans<<1)+(ans<<3)+c-'0',c=getchar(); return ans*w; } const int N=3e5+10; struct Edge{int v,w,next;}E[N<<1]; int head[N],tot=0; int n,m,l=0
,r=0; int cost[N],fro[N],to[N],lca[N]; int dis[N],dep[N],cnt[N],pre[N]; int fa[N][20],Log2[N]; void add(int u,int v,int w){E[++tot]=(Edge){v,w,head[u]};head[u]=tot;} void dfs(int u){ dep[u]=dep[fa[u][0]]+1; fu(i,1,Log2[dep[u]])fa[u][i]=fa[fa[u][i-1]][i-1]; for(int i=head[u];i;i=E[i].next){ int
v=E[i].v; if(v==fa[u][0])continue; pre[v]=i; fa[v][0]=u; dis[v]=dis[u]+E[i].w; dfs(v); } } void redfs(int u){ for(int i=head[u];i;i=E[i].next){ int v=E[i].v; if(v==fa[u][0])continue; redfs(v); cnt[u]+=cnt[v]; } } int LCA(int x,int y){ if(dep[x]<dep[y])swap(x,y); int t=dep[x]-dep[y]; fu(i,0,Log2[t])if(t&(1<<i))x=fa[x][i]; if(x==y)return x; int k=Log2[dep[x]]; while(fa[x][0]!=fa[y][0]){ if(fa[x][k]!=fa[y][k]){ x=fa[x][k]; y=fa[y][k]; } k--; } return fa[x][0]; } bool check(int vl){ int siz=0; fu(i,1,n)cnt[i]=0; fu(i,1,m){ if(cost[i]<=vl)continue; siz++; cnt[fro[i]]++; cnt[to[i]]++; cnt[lca[i]]-=2; } redfs(1); int maxv=0; fu(i,1,n){ if(cnt[i]!=siz)continue; maxv=max(maxv,E[pre[i]].w); } fu(i,1,m)if(cost[i]-maxv>vl)return 0; return 1; } int main(){ n=read();m=read(); Log2[1]=0;fu(i,2,n)Log2[i]=Log2[i>>1]+1; fu(i,1,n-1){ int u=read(),v=read(),w=read(); add(u,v,w); add(v,u,w); } dfs(1); fu(i,1,m){ fro[i]=read(),to[i]=read(); lca[i]=LCA(fro[i],to[i]); cost[i]=dis[fro[i]]+dis[to[i]]-(dis[lca[i]]<<1); r=max(r,cost[i]); } int ans; while(l<=r){ int mid=(l+r*2)/3; if(check(mid))r=mid-1,ans=mid; else l=mid+1; } printf("%d",ans); return 0; }