運輸計劃
運輸計劃
時空限制1000ms-2000ms / 300MB
題目背景
公元 2044 年,人類進入了宇宙紀元。
題目描述
公元2044 年,人類進入了宇宙紀元。
L 國有 n 個星球,還有 n−1 條雙向航道,每條航道建立在兩個星球之間,這 n−1 條航道連通了 L 國的所有星球。
小 P 掌管一家物流公司, 該公司有很多個運輸計劃,每個運輸計劃形如:有一艘物流飛船需要從 ui? 號星球沿最快的宇航路徑飛行到 vi? 號星球去。顯然,飛船駛過一條航道是需要時間的,對於航道 j,任意飛船駛過它所花費的時間為 tj?,並且任意兩艘飛船之間不會產生任何幹擾。
為了鼓勵科技創新, L 國國王同意小 P 的物流公司參與 L 國的航道建設,即允許小P 把某一條航道改造成蟲洞,飛船駛過蟲洞不消耗時間。
在蟲洞的建設完成前小 P 的物流公司就預接了 m 個運輸計劃。在蟲洞建設完成後,這 m 個運輸計劃會同時開始,所有飛船一起出發。當這 m 個運輸計劃都完成時,小 P 的物流公司的階段性工作就完成了。
如果小 P 可以自由選擇將哪一條航道改造成蟲洞, 試求出小 P 的物流公司完成階段性工作所需要的最短時間是多少?
輸入輸出格式
輸入格式:第一行包括兩個正整數 n,m,表示 L 國中星球的數量及小 P 公司預接的運輸計劃的數量,星球從 1 到 n 編號。
接下來 n−1 行描述航道的建設情況,其中第 i 行包含三個整數 ai?,bi? 和 ti?,表示第 i 條雙向航道修建在 ai? 與 bi?兩個星球之間,任意飛船駛過它所花費的時間為 ti?。數據保證 1≤ai?,bi?≤n 且 0≤ti?≤1000。
接下來 m 行描述運輸計劃的情況,其中第 j 行包含兩個正整數 uj? 和 vj?,表示第 j 個運輸計劃是從 uj? 號星球飛往 vj?號星球。數據保證 1≤ui?,vi?≤n
輸出格式:一個整數,表示小 P 的物流公司完成階段性工作所需要的最短時間。
輸入輸出樣例
輸入樣例:6 3 1 2 3 1 6 4 3 1 7 4 3 6 3 5 5 3 6 2 5 4 5
11
說明
所有測試數據的範圍和特點如下表所示
請註意常數因子帶來的程序效率上的影響。
分析:因為是使所有路徑中最大的那個最小,所以可以考慮二分答案。當二分一個答案mid後,統計所有路徑長度大於mid的路徑,再求出所有路徑邊的交集中,邊長最大的那一個,再判斷最長路徑減去最大邊長是否小於等於mid。以上過程可以通過樹上差分來實現。
常數優化:1.鏈式前向星; 2.讀入優化; 3.樹上差分最後統計結果時,可以不用dfs計算結果。先跑一邊dfs把dfs序記錄下來,然後按照dfs序從後向前統計結果。
#include<bits/stdc++.h> #define N 300005 using namespace std; struct edge{int next,v,w;}; edge edg[N*2]; int head[N],now_edge=0; int grand[N][25]={0},gw[N][25]={0}; int depth[N],DEPTH; int dfsorder[N],c1=0; int edge_dfsorder[N]; void addedge(int a,int b,int w) { edg[now_edge]=(edge){head[a],b,w}; head[a]=now_edge++; edg[now_edge]=(edge){head[b],a,w}; head[b]=now_edge++; } void dfs(int x) { dfsorder[c1++]=x; for(int i=1;i<=DEPTH;i++) { grand[x][i]=grand[grand[x][i-1]][i-1]; gw[x][i]=gw[x][i-1]+gw[grand[x][i-1]][i-1]; } for(int i=head[x];i!=-1;i=edg[i].next) { int to=edg[i].v; if(grand[x][0]==to)continue; depth[to]=depth[x]+1; grand[to][0]=x; gw[to][0]=edg[i].w; edge_dfsorder[c1]=i; dfs(to); } } void init(int n) { DEPTH=floor(log(n + 0.0) / log(2.0)); depth[1]=1; memset(grand,0,sizeof(grand)); memset(gw,0,sizeof(gw)); dfs(1); } int lca(int a,int b,int &c) { if(depth[a]>depth[b])swap(a,b); int ans=0; for(int i=DEPTH;i>=0;i--) if(depth[a]<depth[b]&&depth[grand[b][i]]>=depth[a]) ans+=gw[b][i],b=grand[b][i]; for(int i=DEPTH;i>=0;i--) if(grand[a][i]!=grand[b][i]) { ans+=gw[a][i]; ans+=gw[b][i]; a=grand[a][i]; b=grand[b][i]; } if(a!=b) { ans+=gw[a][0]; ans+=gw[b][0]; c=grand[a][0]; } else c=a; return ans; } int cf[N]={0}; int edge_Max=0; int cf_dfs(int tot) { for(int i=c1-1;i>=0;i--) { cf[grand[dfsorder[i]][0]]+=cf[dfsorder[i]]; if(cf[dfsorder[i]]==tot)edge_Max=max(edge_Max,edg[edge_dfsorder[i]].w); } } int from[N],to[N],Lca[N],ancestor[N]; void read(int &x) { int f=1;x=0;char s=getchar(); while(s<‘0‘||s>‘9‘){if(s==‘-‘)f=-1;s=getchar();} while(s>=‘0‘&&s<=‘9‘){x=x*10+s-‘0‘;s=getchar();} x*=f; } int main() { int n,m; memset(head,-1,sizeof(head)); //scanf("%d %d",&n,&m); read(n); read(m); for(int i=1;i<n;i++) { int a,b,c; //scanf("%d %d %d",&a,&b,&c); read(a); read(b); read(c); addedge(a,b,c); } init(n); int Left=0,Right=0,ans,road_Max,tot; for(int i=1;i<=m;i++) { // scanf("%d %d",&from[i],&to[i]); read(from[i]); read(to[i]); Lca[i]=lca(from[i],to[i],ancestor[i]); Right=max(Right,Lca[i]); } while(Left<=Right) { int mid=(Left+Right)/2; edge_Max=-1; road_Max=-1; tot=0; for(int i=1;i<=m;i++) { if(Lca[i]>mid) { road_Max=max(road_Max,Lca[i]); cf[from[i]]++; cf[to[i]]++; cf[ancestor[i]]-=2; tot++; } } if(road_Max==-1) { ans=mid; Right=mid-1; } else { cf_dfs(tot); if(road_Max-edge_Max<=mid) { ans=mid; Right=mid-1; } else Left=mid+1; } if(tot) { for(int i=1;i<=n;i++)cf[i]=0; } } printf("%d",ans); return 0; }View Code
運輸計劃