NOIP2015运输计划(二分答案)
题目描述
公元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的物流公司完成阶段性工作所需要的最短时间。
input
6 3 1 2 3 1 6 4 3 1 7 4 3 6 3 5 5 3 6 2 5 4 5
output
11
样例说明
将第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。
限制与约定
解题思路:
首先考虑一下暴力,在n,m都小于3000时,先将两点间的边权值转化为深度较大的点的权值,利用朴素LCA求出两点间的耗费时间,再枚举删去哪一点枚举m中答案,更新即可
时间复杂度O(n*m),期望得分60分
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 typedef long long lnt; 6 struct pnt{ 7 int hd; 8 int no; 9 int fa; 10 int ol; 11 int dp; 12 lnt val; 13 }p[1000000]; 14 struct ent{ 15 int twd; 16 int lst; 17 lnt tim; 18 }e[1000000]; 19 int cnt; 20 int n,m; 21 lnt ans=0x7f7f7f7f7f7f7f7fll; 22 int u[300001]; 23 int v[300001]; 24 int tf[300001]; 25 int hv[3005][3005]; 26 void ade(int f,int t,lnt y) 27 { 28 cnt++; 29 e[cnt].twd=t; 30 e[cnt].lst=p[f].hd; 31 p[f].hd=cnt; 32 e[cnt].tim=y; 33 } 34 void dfs(int x,int f) 35 { 36 p[x].dp=p[f].dp+1; 37 p[x].fa=f; 38 for(int i=p[x].hd;i;i=e[i].lst) 39 { 40 int to=e[i].twd; 41 if(to!=f) 42 { 43 p[to].val=e[i].tim; 44 dfs(to,x); 45 } 46 } 47 return ; 48 } 49 int main() 50 { 51 scanf("%d%d",&n,&m); 52 for(int i=1;i<n;i++) 53 { 54 int a,b; 55 lnt c; 56 scanf("%d%d%lld",&a,&b,&c); 57 ade(a,b,c); 58 ade(b,a,c); 59 } 60 dfs(1,1); 61 for(int i=1;i<=m;i++) 62 { 63 scanf("%d%d",&u[i],&v[i]); 64 } 65 if(m==1) 66 { 67 lnt mtmp=0; 68 lnt mins=0; 69 int x=u[1]; 70 int y=v[1]; 71 if(p[x].dp<p[y].dp) 72 swap(x,y); 73 while(p[x].dp!=p[y].dp) 74 { 75 mtmp+=p[x].val; 76 mins=max(mins,p[x].val); 77 x=p[x].fa; 78 } 79 if(x==y) 80 { 81 printf("%lld\n",mtmp-mins); 82 return 0; 83 } 84 while(x!=y) 85 { 86 mins=max(mins,p[x].val); 87 mins=max(mins,p[y].val); 88 mtmp+=p[x].val; 89 x=p[x].fa; 90 mtmp+=p[y].val; 91 y=p[y].fa; 92 } 93 printf("%lld\n",mtmp-mins); 94 return 0; 95 } 96 for(int i=1;i<=m;i++) 97 { 98 lnt mtmp=0; 99 int x=u[i]; 100 int y=v[i]; 101 if(p[x].dp<p[y].dp) 102 swap(x,y); 103 while(p[x].dp!=p[y].dp) 104 { 105 hv[i][x]=1; 106 mtmp+=p[x].val; 107 x=p[x].fa; 108 } 109 if(x==y) 110 { 111 tf[i]=mtmp; 112 continue; 113 } 114 while(x!=y) 115 { 116 hv[i][x]=1; 117 hv[i][y]=1; 118 mtmp+=p[x].val; 119 x=p[x].fa; 120 mtmp+=p[y].val; 121 y=p[y].fa; 122 } 123 tf[i]=mtmp; 124 } 125 for(int i=2;i<=n;i++) 126 { 127 lnt maxs=0; 128 for(int j=1;j<=m;j++) 129 { 130 maxs=max(maxs,tf[j]-(lnt)hv[j][i]*p[i].val); 131 } 132 ans=min(ans,maxs); 133 } 134 printf("%lld\n",ans); 135 return 0; 136 }
正解:
二分答案+树上打差分
将计划排序。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 typedef long long lnt; 6 struct pnt{ 7 int fa; 8 int dp; 9 int hd; 10 int ola; 11 int sgrl; 12 lnt dis; 13 }p[1000000]; 14 struct ent{ 15 int twd; 16 int lst; 17 lnt vls; 18 }e[1000000]; 19 struct qnt{ 20 int u; 21 int v; 22 lnt dtc; 23 }q[10000000]; 24 int n,m; 25 int cnt; 26 int ont; 27 int lsd; 28 int top; 29 int old[20][1000000]; 30 int lg[2000000]; 31 int lns[2000000]; 32 int lfs[2000000]; 33 bool cmp(qnt x,qnt y) 34 { 35 return x.dtc>y.dtc; 36 } 37 void ade(int f,int t,lnt v) 38 { 39 cnt++; 40 e[cnt].twd=t; 41 e[cnt].lst=p[f].hd; 42 e[cnt].vls=v; 43 p[f].hd=cnt; 44 } 45 void dfs_build(int x,int f) 46 { 47 old[0][++ont]=x; 48 p[x].fa=f; 49 p[x].dp=p[f].dp+1; 50 p[x].ola=ont; 51 bool flag=1; 52 for(int i=p[x].hd;i;i=e[i].lst) 53 { 54 int to=e[i].twd; 55 if(to!=f) 56 { 57 flag=false; 58 p[to].dis=p[x].dis+e[i].vls; 59 dfs_build(to,x); 60 old[0][++ont]=x; 61 } 62 } 63 if(flag) 64 { 65 lfs[++lsd]=x; 66 } 67 } 68 void Tr_dfs(int x,int f) 69 { 70 for(int i=p[x].hd;i;i=e[i].lst) 71 { 72 int to=e[i].twd; 73 if(to!=f) 74 { 75 Tr_dfs(to,x); 76 p[x].sgrl+=p[to].sgrl; 77 } 78 } 79 return ; 80 } 81 int rmaxs(int x,int y) 82 { 83 return p[x].dp>p[y].dp?y:x; 84 } 85 int lca(int x,int y) 86 { 87 if(p[x].ola>p[y].ola) 88 swap(x,y); 89 int lgg=lg[p[y].ola-p[x].ola+1]; 90 return rmaxs(old[lgg][p[x].ola],old[lgg][p[y].ola-(1<<lgg)+1]); 91 } 92 int Ccl(int agc) 93 { 94 int x=0; 95 while(agc<q[x+1].dtc)x++; 96 if(lns[x])return lns[x]; 97 for(int i=1;i<=n;i++) 98 p[i].sgrl=0; 99 for(int i=1;i<=x;i++) 100 { 101 p[q[i].u].sgrl++; 102 p[q[i].v].sgrl++; 103 p[lca(q[i].v,q[i].u)].sgrl-=2; 104 } 105 Tr_dfs(1,1); 106 lnt ans=0; 107 for(int i=1;i<=n;i++) 108 { 109 if(p[i].sgrl==x) 110 { 111 ans=max(ans,p[i].dis-p[p[i].fa].dis); 112 } 113 } 114 lns[x]=ans; 115 return ans; 116 } 117 int main() 118 { 119 scanf("%d%d",&n,&m); 120 for(int i=1;i<n;i++) 121 { 122 int x,y; 123 int z; 124 scanf("%d%d%d",&x,&y,&z); 125 ade(x,y,z); 126 ade(y,x,z); 127 } 128 for(int i=2;i<=3*n;i++) 129 { 130 lg[i]=lg[i/2]+1; 131 } 132 dfs_build(1,1); 133 for(int i=1;i<=20;i++) 134 for(int j=1;j+(1<<i)-1<=ont;j++) 135 old[i][j]=rmaxs(old[i-1][j],old[i-1][j+(1<<i-1)]); 136 for(int i=1;i<=m;i++) 137 { 138 scanf("%d%d",&q[i].u,&q[i].v); 139 q[i].dtc=p[q[i].u].dis+p[q[i].v].dis-2*p[lca(q[i].v,q[i].u)].dis; 140 } 141 sort(q+1,q+m+1,cmp); 142 int l=0; 143 int r=q[1].dtc; 144 int ans; 145 while(l<=r) 146 { 147 int mid=(l+r)>>1; 148 if(q[1].dtc-Ccl(mid)>mid)l=mid+1; 149 else{ 150 ans=mid; 151 r=mid-1; 152 } 153 } 154 printf("%d\n",ans); 155 return 0; 156 }