运输计划NOIP2015Day2T3
运输计划
题目描述
公元 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。 接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 uj 和 vj,表示第 j 个
运输计划是从 uj 号星球飞往 vj 号星球。
输出
共 1 行,包含 1 个整数,表示小 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
提示
solution:
首先,想到的是一个暴力的做法:枚举哪一条边的权值改为0,然后tarjan求LCA,算出树上最短路,统计答案。时间复杂度O(n²),可以得到50分。11、12个点m=1,可以随便乱搞。13~16是一条链,又是求“最大值最小”,很容易想到二分答案+差分。这样子可以轻松骗到80分。
再来想正解,发现其实一棵树的情况也可以用与一条链类似的方法做。先用tarjan求出LCA,然后还是二分答案,将代价大于mid的询问视为有用询问,没用的询问不用管,差分不再是在一条链上了,要树上差分,即a[x]++,a[y]++,a[LCA(x,y)]-=2,然后递归累加a数组,就可以求出每一条边被几组有用的询问经过。为了使所有的询问代价小于等于mid,而有用询问的代价都是大于mid的,所以只有被所以有用询问经过的边才可能被变为虫洞。为了让最大的代价最小,显然应该将可能变为虫洞的边中权值最大的那条变为虫洞,这样子就可以判断答案了。
时间复杂度O(n+n lg n)=O(n lg n),AC!
code
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<algorithm> 5 #include<cstdlib> 6 #include<cstring> 7 #include<vector> 8 using namespace std; 9 int MAX,Max,num,l,r,mid,aa[1000005],qx[1000005],qy[1000005],ans,ans1,X[1000005],Y[1000005],Z[1000005],T,n,m,color[1000005],fa[1000005],qa[1000005],qb[1000005],deep[1000005]; 10 vector<pair<int,int> > question[1000005]; 11 vector<pair<int,pair<int,int> > > edge[1000005]; 12 vector<pair<int,int> >::iterator beg[1000005]; 13 bool vis[1000005]; 14 int get(int x){ 15 if(x==fa[x]) 16 return x; 17 return fa[x]=get(fa[x]); 18 } 19 void dfs(int u,int emperor){ 20 color[u]=1; 21 for(vector<pair<int,pair<int,int> > >::iterator i=edge[u].begin();i!=edge[u].end();i++) 22 if(!color[i->first]){ 23 deep[i->first]=deep[u]+i->second.first; 24 dfs(i->first,emperor); 25 fa[i->first]=u; 26 } 27 color[u]=2; 28 for(vector<pair<int,int> >::iterator i=question[u].begin();i!=question[u].end();i++) 29 if(color[i->first]==2) 30 i->second=get(i->first); 31 } 32 void dfs(int u){ 33 for(vector<pair<int,pair<int,int> > >::iterator i=edge[u].begin();i!=edge[u].end();i++){ 34 int v=i->first; 35 if(!vis[v]){ 36 vis[v]=true; 37 dfs(v); 38 i->second.second=aa[v]; 39 aa[u]+=aa[v]; 40 } 41 } 42 } 43 int main(){ 44 scanf("%d%d",&n,&m); 45 for(int i=1;i<n;i++) 46 scanf("%d%d%d",&X[i],&Y[i],&Z[i]); 47 for(int i=1;i<=m;i++) 48 scanf("%d%d",&qx[i],&qy[i]); 49 for(int i=1;i<n;i++){ 50 int x=X[i],y=Y[i],z=Z[i]; 51 edge[x].push_back(make_pair(y,make_pair(z,0))); 52 edge[y].push_back(make_pair(x,make_pair(z,0))); 53 } 54 for(int i=1;i<=m;i++){ 55 int x=qx[i],y=qy[i]; 56 qa[i]=x; 57 qb[i]=y; 58 question[x].push_back(make_pair(y,0)); 59 question[y].push_back(make_pair(x,0)); 60 } 61 for(int i=1;i<=n;i++) 62 fa[i]=i; 63 dfs(1,1); 64 for(int i=1;i<=n;i++) 65 beg[i]=question[i].begin(); 66 l=0; 67 r=1000000000; 68 while(l<r){ 69 mid=(l+r)>>1; 70 num=0; 71 for(int i=1;i<=n;i++) 72 aa[i]=0,vis[i]=false; 73 MAX=0; 74 for(int i=1;i<=n;i++) 75 beg[i]=question[i].begin(); 76 for(int i=1;i<=m;i++){ 77 int x,y; 78 x=qa[i]; 79 y=qb[i]; 80 if(deep[x]+deep[y]-2*deep[max(beg[x]->second,beg[y]->second)]>mid){ 81 MAX=max(MAX,deep[x]+deep[y]-2*deep[max(beg[x]->second,beg[y]->second)]); 82 num++; 83 aa[x]++; 84 aa[y]++; 85 aa[max(beg[x]->second,beg[y]->second)]-=2; 86 } 87 beg[x]++; 88 beg[y]++; 89 } 90 dfs(1); 91 Max=0; 92 for(int i=1;i<=n;i++) 93 for(vector<pair<int,pair<int,int> > >::iterator it=edge[i].begin();it!=edge[i].end();it++) 94 if(it->second.second==num) 95 Max=max(Max,it->second.first); 96 if(MAX-Max>mid) 97 l=mid+1; 98 else 99 r=mid; 100 } 101 printf("%d\n",r); 102 return 0; 103 }