P2680 運輸計劃 A-二分答案-樹上邊差分
阿新 • • 發佈:2018-12-03
- https://www.luogu.org/problemnew/show/P2680
- 題意:首先這是一棵n個節點的樹,然後對於樹上的m條鏈,我們可以選取樹上的唯一一條邊使它的邊權變為0
- 求處理後最長鏈的長度,要求使得最後最長鏈長度最小,最大值最小問題,二分答案
- 思路:二分答案肯定是二分的時間,然後關鍵是預處理與二分的check怎麼實現。預處理可以通過LCA 求出樹上任意兩點
- 的距離,然後可以對m條鏈進行一下預處理出每條的長度,check時檢驗哪些邊長度超過了當前列舉的答案,然後對這些
- 邊進行差分更新,跑一邊dfs更新答案,因為我們只對長度大於當前列舉答案的那些邊進行更新差分陣列,所以為了能夠
- 最終達到一個合法狀態,刪除的邊至少得滿足(這些長度大於當前答案的鏈 都經過這條邊)所以我們的更新條件為:
-
if(power[edge[i].v]==sp&&edge[i].w>ans)ans=edge[i].w;
- 求一個經過這條邊的非法的鏈的數目為sp 並且 邊值最大的刪掉是最優的
-
#include<bits/stdc++.h> using namespace std; #define ll long long #define maxn 301212 int n,m,a,b,t,u,v,cnt,c; int head[maxn],deep[maxn]; int dp[maxn][50],power[maxn]; ll ans,dis[maxn],L,R,mid,sp; struct node { int v,to,w; } edge[maxn]; struct edg { int x,y,z; } orz[maxn]; struct data { int u,v,fa; ll sum; bool operator<(const data&b)const { return sum>b.sum; } } lhk[maxn]; void add(int u,int v,int w) { edge[++cnt].v=v; edge[cnt].to=head[u]; edge[cnt].w=w; head[u]=cnt; } void dfs(int cur,int fa) { deep[cur]=deep[fa]+1; dp[cur][0]=fa; for(int j=1; (1<<j)<=deep[cur]; j++) dp[cur][j]=dp[dp[cur][j-1]][j-1]; for(int i=head[cur]; i!=-1; i=edge[i].to) { if(edge[i].v==fa)continue; dis[edge[i].v]=dis[cur]+edge[i].w; dfs(edge[i].v,cur); } } int lca(int x,int y) { if(deep[x]<deep[y])swap(x,y); for(int i=30; i>=0; i--) if(deep[y]+(1<<i)<=deep[x]) x=dp[x][i]; if(x==y)return x; for(int i=30; i>=0; i--) if(dp[x][i]!=dp[y][i]) { x=dp[x][i]; y=dp[y][i]; } return dp[x][0]; } void get(int cur,int fa) { for(int i=head[cur]; i!=-1; i=edge[i].to) { if(edge[i].v==fa)continue; get(edge[i].v,cur); power[cur]+=power[edge[i].v]; if(power[edge[i].v]==sp&&edge[i].w>ans)ans=edge[i].w; } } bool ok(ll cur) { memset(power,0,sizeof(power)); if(lhk[0].sum<=cur)return true; bool flag=0; sp=ans=0; for(int i=0; i<m; i++) { if(lhk[i].sum<=cur) break; power[lhk[i].u]++; power[lhk[i].v]++; power[lhk[i].fa]-=2; sp++; } get(1,0); if(lhk[0].sum-ans>cur)return 0; return 1; } int main() { memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); for(int i=1; i<n; i++) { scanf("%d%d%d",&u,&v,&c); add(u,v,c); add(v,u,c); orz[i].x=u; orz[i].y=v; orz[i].z=c; } dis[1]=deep[0]=0; dfs(1,0); for(int i=0; i<m; i++) { scanf("%d%d",&lhk[i].u,&lhk[i].v); int qyn=lca(lhk[i].u,lhk[i].v); lhk[i].sum=dis[lhk[i].u]+dis[lhk[i].v]-2*dis[qyn]; lhk[i].fa=qyn; } ans=0; sort(lhk,lhk+m); R=1e12; L=0; while(L<R) { mid=(L+R)/2; if(ok(mid))R=mid; else L=mid+1; } printf("%lld\n",L); return 0; }