博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[UOJ409]Highway Tolls
阅读量:6936 次
发布时间:2019-06-27

本文共 3264 字,大约阅读时间需要 10 分钟。

题意:交互题,给定一个简单无向图和$A,B(1\leq A\lt B)$,你可以对每条边指定其边权为$A$或$B$后通过交互库询问$S\rightarrow T$的最短路($S,T$在程序运行之前已经确定),但你不知道$S,T$,现在要求$S$和$T$

无论是什么做法,我们首先需要知道边权为$1$时的最短路$dis$,在开始时把所有边设为$A$,调用一次即可

从部分分入手,第一个部分分(subtask1,2):图是一棵树,已知根是$S$,求$T$

因为只能调用很少次交互库,所以考虑二分

我们在bfs序上二分,假设当前二分到$[l,r]$,我们要检查$T$的bfs序是否在$[l,mid]$中,如果我们将bfs序在$[1,mid]$中的点的祖先边全部设为$A$,将其他边设为$B$,并且此时最短路为$dis\cdot A$,那么显然$T$的bfs序在$[l,mid]$中(因为任何bfs序在$[mid+1,r]$中的节点到根至少经过一条$B$边),于是时间复杂度为$O(n\log n)$,调用次数为$1+\left\lceil\log_2n\right\rceil$

然后是第二个部分分(subtask3,4):图是一棵树

如果我们能找出一条在$S\rightarrow T$最短路上的边,那么删掉这条边后对两棵树套用上面的算法即可

要找到任意一条这样的边,还是得二分,二分边的编号,二分到$[l,r]$时把$[1,mid]$的边设为$B$,把$[mid+1,n-1]$的边设为$A$,如果最短路没有变化,那么这条边在$[mid+1,r]$,否则在$[l,mid]$,于是时间复杂度为$O(n\log_2n)$,调用次数为$1+\left\lceil\log_2n\right\rceil+2\left\lceil\log_2\frac n2\right\rceil$

然后是一般情况(subtask5,6)

我们同样想找到一条在$S\rightarrow T$的任意一条最短路上的边,还是得二分边的编号,一开始把所有边设为$A$,二分到$[l,r]$时先把$[l,mid]$设为$B$,查询最短路,如果最短路变化了,那么$[l,mid]$中一定有这样的边,于是先把$[l,mid]$设回$A$,再去$[l,mid]$中寻找答案,否则它就在$[mid+1,r]$了

假设我们找出来的边是$(x,y)$,我们用这条边构造两个不相交的集合$S_1,S_2$(以下的距离都是边权为$1$的距离)

如果一个点$u$满足$dis_{u,x}<dis_{u,y}$,那么$u\in S_1$,如果$u$满足$dis_{u,x}\gt dis_{u,y}$,那么$u\in S_2$

在$S_1$中以$x$为根构造bfs树,在$S_2$中以$y$为根构造bfs树,那么$S\rightarrow T$一定存在一条最短路是只经过树边和$(x,y)$的

将非树边设为$B$,将树边和$(x,y)$设为$A$,那么接下来要做的事情就和第二个部分分的最后一步一样了

总时间复杂度$O\left(m(\log m+\log n)\right)$,调用次数为$1+\left\lceil\log_2m\right\rceil+2\left\lceil\log_2\frac n2\right\rceil$,刚好是$50$,但官方数据好像并没有卡满...

神仙图论题...

#include"highway.h"#include
#include
#include
using namespace std;typedef long long ll;const int inf=2147483647;int abs(int x){return x>0?x:-x;}int h[90010],nex[260010],to[260010],id[260010],M,n,m;void add(int a,int b,int c){ M++; to[M]=b; id[M]=c; nex[M]=h[a]; h[a]=M;}int q[90010],d1[90010],d2[90010];void getdis(int*d,int x){ int head,tail,i; for(i=1;i<=n;i++)d[i]=inf; head=tail=1; q[1]=x; d[x]=0; while(head<=tail){ x=q[head++]; for(i=h[x];i;i=nex[i]){ if(d[x]+1
u,v,w;int fa[90010],bfn[90010];bool t1[260010],t2[260010];void bfs(int x,bool*t){ int head,tail,i; head=tail=1; q[1]=x; M=0; while(head<=tail){ x=q[head++]; bfn[x]=++M; for(i=h[x];i;i=nex[i]){ if(to[i]!=fa[x]&&t[i]){ fa[to[i]]=x; q[++tail]=to[i]; } } }}ll dis;int solve(int x,int y,bool*t){ memset(fa,0,sizeof(fa)); memset(bfn,0,sizeof(bfn)); int l,r,mid,ans,i; fa[y]=x; bfs(y,t); l=1; r=M; ans=0; while(l<=r){ mid=(l+r)>>1; for(i=0;i
mid; } } if(ask(w)==dis){ ans=mid; r=mid-1; }else l=mid+1; } for(i=1;i<=n;i++){ if(bfn[i]==ans)break; } return i;}int sfa[90010];int get(int x){return x==sfa[x]?x:(sfa[x]=get(sfa[x]));}void buildt1(int x){ int head,tail,i; for(i=1;i<=n;i++)sfa[i]=i; head=tail=1; q[1]=x; while(head<=tail){ x=q[head++]; for(i=h[x];i;i=nex[i]){ if(d1[x]
d2[x]&&d1[to[i]]>d2[to[i]]&&d2[x]!=d2[to[i]]&&get(x)!=get(to[i])){ t2[i]=t2[((i-1)^1)+1]=1; sfa[get(to[i])]=get(x); q[++tail]=to[i]; } } }}void find_pair(int n,vector
u,vector
v,int A,int B){ int i,x,y,l,r,mid; m=u.size(); w.resize(m); for(i=0;i
>1; for(i=l;i<=mid;i++)w[i]=1; if(ask(w)!=dis){ for(i=l;i<=mid;i++)w[i]=0; r=mid; }else l=mid+1; } x=u[l]; y=v[l]; getdis(d1,x); getdis(d2,y); buildt1(x); buildt2(y); t1[l*2+1]=t1[l*2+2]=t2[l*2+1]=t2[l*2+2]=1; answer(solve(x,y,t2)-1,solve(y,x,t1)-1);}

转载于:https://www.cnblogs.com/jefflyy/p/9674412.html

你可能感兴趣的文章
2017.4.24 js 中的iscroll
查看>>
递归法
查看>>
sass入门篇
查看>>
中英混排做字符串精确截取
查看>>
Java类型转换实例 分类: Java 201...
查看>>
.NET Core IdentityServer4实战-开篇介绍与规划
查看>>
C++ 知识点汇总
查看>>
javascript中元素的scrollLeft和scrollTop属性说明
查看>>
jquery获取对象
查看>>
2018年全国多校算法寒假训练营练习比赛(第二场)B - TaoTao要吃鸡
查看>>
别在迷恋正则表达式解析html了,好吗?
查看>>
【ZJOI 2008】树的统计 Count
查看>>
Window7系统 中常见的进程命令分析?
查看>>
二、观察者模式
查看>>
multimap删除
查看>>
笔记2011.7.12
查看>>
好插件让你事半功倍!【资源篇】
查看>>
(转)SplitContainer 控件(Windows 窗体)
查看>>
【转】PHP foreach 小结
查看>>
【转】如何用Redis做LRU-Cache
查看>>