題目描述 傳送門
L 國有 n 個星球,還有 n-1 條雙向航道,每條航道建立在兩個星球之間,這 n-1 條航道連通了 L 國的所有星球。
小 P 掌管一家物流公司,該公司有很多個運輸計劃,每個運輸計劃形如:有一艘物
流飛船需要從 ui 號星球沿最快的宇航路徑飛行到 vi 號星球去。顯然,飛船駛過一條航道 是需要時間的,對於航道 j,任意飛船駛過它所花費的時間爲 tj,並且任意兩艘飛船之 間不會產生任何干擾。
爲了鼓勵科技創新,L 國國王同意小 P 的物流公司參與 L 國的航道建設,即允許小 P 把某一條航道改造成蟲洞,飛船駛過蟲洞不消耗時間。
在蟲洞的建設完成前小 P 的物流公司就預接了 m 個運輸計劃。在蟲洞建設完成後, 這 m 個運輸計劃會同時開始,所有飛船一起出發。當這 m 個運輸計劃都完成時,小 P 的 物流公司的階段性工作就完成了。
如果小 P 可以自由選擇將哪一條航道改造成蟲洞,試求出小 P 的物流公司完成階段時要的最短時間是多少?
樹鏈剖分+線段樹暴力嘗試修改所有路徑40分,,,
正解:二分答案+樹上差分+LCA(我用的樹鏈剖分)
大致思路是:先把無根樹轉化成有根樹,預處理lca和運輸的路徑長,然後二分答案,對於大於二分答案的路徑,需要嘗試刪除其中一條邊來滿足答案,易知需要刪除的邊一定是這些路徑的交集,利用樹上差分求出每條邊被多少條大於答案的路徑覆蓋,方法是把一條
代碼
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=3e5+10;
int n,m;
struct Edge{
int to,nxt,d;
Edge(int a=0,int b=0,int c=0):to(a),nxt(b),d(c){}
}v[maxn*2];
int len=0,cnt=0,l=-1,r=0;
int h[maxn],fa[maxn],sz[maxn],son[maxn],lca[maxn],seq[maxn],dist[maxn],cost[maxn],depth[maxn],top[maxn],s[maxn],t[maxn],sum[maxn];
void dfs1(int u,int f){
fa[u]=f;
sz[u]=1;
son[u]=0;
depth[u]=depth[f]+1;
for(int i=h[u];i;i=v[i].nxt) if(v[i].to!=f){
dist[v[i].to]=dist[u]+v[i].d;
dfs1(v[i].to,u);
sz[u]+=sz[v[i].to];
if(sz[v[i].to]>sz[son[u]]) son[u]=v[i].to;
}
seq[len++]=u;
}
void dfs2(int u,int tp){
top[u]=tp;
if(sz[u]>1) dfs2(son[u],tp);
for(int i=h[u];i;i=v[i].nxt) if(v[i].to!=fa[u]&&v[i].to!=son[u])
dfs2(v[i].to,v[i].to);
}
int getlca(int x,int y){
int f1=top[x],f2=top[y],ans=0;
while(f1!=f2){
if(depth[f1]<depth[f2]) swap(f1,f2),swap(x,y);
x=fa[f1];
f1=top[x];
}
if(x==y) return x;
if(depth[x]<depth[y]) swap(x,y);
return y;
}
bool check(int a){
memset(sum,0,sizeof(sum));
int tot=0,ans=0;
for(int i=0;i<m;i++) if(cost[i]>a){
sum[lca[i]]-=2;
sum[s[i]]++;
sum[t[i]]++;
tot++;
}
for(int i=0;i<len;i++) sum[fa[seq[i]]]+=sum[seq[i]];
for(int i=2;i<=n;i++) if(sum[i]==tot) ans=max(ans,dist[i]-dist[fa[i]]);
for(int i=0;i<m;i++) if(cost[i]-ans>a) return false;
return true;
}
int main(){
scanf("%d%d",&n,&m);
memset(h,0,sizeof(h));
for(int i=1;i<n;i++){
int a,b,w;
scanf("%d%d%d",&a,&b,&w);
v[++cnt]=Edge(b,h[a],w);
h[a]=cnt;
v[++cnt]=Edge(a,h[b],w);
h[b]=cnt;
r+=w;
}
depth[1]=sz[0]=dist[1]=0;
dfs1(1,1);
dfs2(1,1);
for(int i=0;i<m;i++){
scanf("%d%d",&s[i],&t[i]);
lca[i]=getlca(s[i],t[i]);
cost[i]=dist[s[i]]+dist[t[i]]-2*dist[lca[i]];
}
while(l<r-1){
int mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid;
}
printf("%d\n",r);
return 0;
}