NOIP2015DAY2T3【運輸計劃】

Description

公元 2044 年,人類進入了宇宙紀元。

L 國有 n 個星球,還有 n−1 條雙向航道,每條航道建立在兩個星球之間,這 n−1 條航道連通了 L 國的所有星球。

小 P 掌管一家物流公司, 該公司有很多個運輸計劃,每個運輸計劃形如:有一艘物流飛船需要從 ui 號星球沿最快的宇航路徑飛行到 vi 號星球去。顯然,飛船駛過一條航道是需要時間的,對於航道 j,任意飛船駛過它所花費的時間爲 tj,並且任意兩艘飛船之間不會產生任何干擾。

爲了鼓勵科技創新, L 國國王同意小 P 的物流公司參與 L 國的航道建設,即允許小P 把某一條航道改造成蟲洞,飛船駛過蟲洞不消耗時間。

在蟲洞的建設完成前小 P 的物流公司就預接了 m 個運輸計劃。在蟲洞建設完成後,這 m 個運輸計劃會同時開始,所有飛船一起出發。當這 m 個運輸計劃都完成時,小 P 的物流公司的階段性工作就完成了。

如果小 P 可以自由選擇將哪一條航道改造成蟲洞, 試求出小 P 的物流公司完成階段性工作所需要的最短時間是多少?

Input Format

第一行包括兩個正整數 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

Output Format

輸出文件只包含一個整數,表示小 P 的物流公司完成階段性工作所需要的最短時間。

Sample Input

6 3
1 2 3
1 6 4
3 1 7
4 3 6
3 5 5
3 6
2 5
4 5

Sample Output

11

Hint

將第 1 條航道改造成蟲洞: 則三個計劃耗時分別爲:11,12,11,故需要花費的時間爲 12。

將第 2 條航道改造成蟲洞: 則三個計劃耗時分別爲:7,15,11,故需要花費的時間爲 15。

將第 3 條航道改造成蟲洞: 則三個計劃耗時分別爲:4,8,11,故需要花費的時間爲 11。

將第 4 條航道改造成蟲洞: 則三個計劃耗時分別爲:11,15,5,故需要花費的時間爲 15。

將第 5 條航道改造成蟲洞: 則三個計劃耗時分別爲:11,10,6,故需要花費的時間爲 11。

故將第 3 條或第 5 條航道改造成蟲洞均可使得完成階段性工作的耗時最短,需要花費的時間爲 11。 


【題解】

 二分答案+在線lca

 由於答案很難直接算出來運用二分答案將問題轉化爲可行性

 若經改造之後m條路徑的長度都小於ans則ans可行

接下來考慮如何算每條路徑長度及刪除哪條邊

求路徑可以在樹上倍增求lca時實現dist=dist[u]+dist[v]-2*dist[lca(u,v)](不會lca歡迎觀看本博客其他lca文章中的詳細介紹)(我這題是用離線lca tarjan大家可以自行百度)

假設未改造之前有k條路徑長度大於ans那麼肯定是刪除被k條路徑都經過的最長邊最優

首先考慮如何找到被k條路徑都經過的邊  可以用差分打標記的方法 在u,v節點各打上1,在lca(u,v)打上-1 用dfs遍歷一遍(樹型動規)

然後把所有經過k次的邊挑出來,排序一下找最長邊,這條邊就是刪除的邊,若最大路徑長-刪除邊邊長<=ans,ans就可行

詳見代碼(好像有點冗餘部分)

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cstdio>
#include <queue>
#include <ctime>
#include <cmath>
using namespace std;
int firstr[300005],firstq[300005],lca[300005],rec[300005],vis[300005],fa[300005],numr,numq;
int dis[300005],f[600005],a[300005];
int i,j,k,l,m,n,r,mid,ans,x,y,z;
struct info
  {
  	int fr,ar,l,next;
  }road[600005],ques[600005];
void add(int x,int y,int z)
  {
  	numr++;road[numr]=(info){x,y,z,firstr[x]};firstr[x]=numr;
  }
void add1(int x,int y,int z)
  {
  	numq++;ques[numq]=(info){x,y,z,firstq[x]};firstq[x]=numq;
  }

int getfa(int x)
  {
  	if (fa[x]==x) return x;else return fa[x]=getfa(fa[x]);
  }
void tarjan(int u)
  {
  	int i,v;
  	vis[u]=1;fa[u]=u;
  	for (i=firstq[u];i;i=ques[i].next)
  	  {
		v=ques[i].ar;
		if (vis[v]) 
		  {
		  	lca[ques[i].l]=getfa(v);
		  	rec[ques[i].l]=dis[u]+dis[v]-2*dis[lca[ques[i].l]];
		  }
	  }
	for (i=firstr[u];i;i=road[i].next)
  	  {
		v=road[i].ar;
		if (!vis[v]) 
		  {
		  	dis[v]=dis[u]+road[i].l;
		  	tarjan(v);
		  	fa[getfa(v)]=u;
		  }
	  }
  }
void dfs(int u,int fa)
  {
    int i;
    for (i=firstr[u];i;i=road[i].next)
      if (road[i].ar!=fa)
        {
           dfs(road[i].ar,u);
           a[u]+=a[road[i].ar];
           f[i]=a[road[i].ar];
		}
  }
bool pd(int l)
  {
  	int i,j,k,mx;
  	memset(a,0,sizeof(a));
  	memset(f,0,sizeof(f));
  	for (i=1,k=0;i<=m;i++)
	   if (rec[i]>l) 
	    {
	      k++;a[ques[2*i].fr]++;a[ques[2*i].ar]++;a[lca[i]]-=2;
		}
  	dfs(1,-1);
  	for (i=1,mx=0;i<=numr;i++)
  	  if (f[i]==k) mx=max(mx,road[i].l);
  	for (i=1;i<=m;i++) if (rec[i]-mx>l) return 0;
  	return 1;
  }
int main()
  {
  	scanf("%d%d",&n,&m);
  	for (i=1;i<n;i++) 
	  scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);
	for (i=1;i<=m;i++) 
	  scanf("%d%d",&x,&y),add1(x,y,i),add1(y,x,i);
	tarjan(1);
    for (i=1;i<=m;i++) r=max(r,rec[i]);
    for (;l<=r;)
      {
      	mid=(l+r)/2;
      	if (pd(mid)) r=mid-1,ans=mid;else l=mid+1;
	  }
	printf("%d",ans);
  } 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章