题目链接:

IOI2018highway

题目大意:给出一张$n$个点$m$条边的无向图,并给出一对未知的起点和终点,每条边都有两种边权$A$和$B$(每条边的$A$和$B$都分别相同),每次你可以设置每条边的边权并向交互库询问,交互库会返回给你当前边权下起点到终点的最短路,你需要在不多于$50$次的询问后找出起点和终点。

我们设起点为$S$,终点为$T$。

首先需要一次询问将边权都设为$A$来知道$S$到$T$的最短路。然后我们可以用二分来找到一个处于$S$到$T$最短路上的点:每次将编号在$[0,mid]$的点的所有出边设为$B$,其他的设为$A$。如果得到的最短路不变,那么显然编号在$[mid+1,n-1]$的点有处于$S$到$T$最短路上的点,反之编号在$[0,mid]$的点有处于$S$到$T$最短路上的点。我们设找到的这个点为$x$,那么$S$与$T$中一定有一个点距离$x$较远,我们设这个点为$S$。从$x$开始$bfs$,二分然后每次将$bfs$序的$[mid+1,n-1]$这些点的所有出边设为$B$,其他边设为$A$,这样就能找到$S$,再从$S$开始$bfs$同样二分$bfs$序找到$T$。这样询问次数是$3*log_{2}^{90000}+1=52$,可以得到$90$分。

既然第一步可以二分找到最短路上的一个点,那么我们同样也可以找到一条边。每次将编号在$[0,mid]$的边设为$B$其他边设为$A$来找到最短路上的一条边,对于这条边的两端点$(u,v)$显然每个点到这两个点的最短距离不同,我们按每个点到这两个点的最短距离将离$u$更近的分为一部分,离$v$更近的分为另一部分,对于每部分还是二分$bfs$序来分别找到$S$和$T$,这样最坏情况询问次数为$1+log_{2}^{130000}+2*log_{2}^{45000}=50$,即可得到满分。

#include"highway.h"
#include<queue>
#include<cstdio>
#include<vector>
#include<algorithm>
#define ll long long
using namespace std;
vector<int>s[90010];
vector<int>to[90010];
int w[130010];
ll path;
queue<int>q;
int dis_u[90010];
int dis_v[90010];
int que_u[90010];
int que_v[90010];
int cnt_u;
int cnt_v;
int S,T;
bool cmp_u(int x,int y)
{
return dis_u[x]<dis_u[y];
}
bool cmp_v(int x,int y)
{
return dis_v[x]<dis_v[y];
}
void find_pair(int n,vector<int> u,vector<int> v,int A,int B)
{
int num=u.size();
for(int i=0;i<num;i++)
{
s[u[i]].push_back(i);
to[u[i]].push_back(v[i]);
s[v[i]].push_back(i);
to[v[i]].push_back(u[i]);
}
path=ask(vector<int>(w,w+num));
int l=0;
int r=num-1;
while(l<r)
{
int mid=(l+r)>>1;
for(int i=0;i<num;i++)
{
w[i]=0;
}
for(int i=0;i<=mid;i++)
{
w[i]=1;
}
ll value=ask(vector<int>(w,w+num));
if(value==path)
{
l=mid+1;
}
else
{
r=mid;
}
}
q.push(u[l]);
dis_u[u[l]]=1;
while(!q.empty())
{
int now=q.front();
q.pop();
int len=to[now].size();
for(int i=0;i<len;i++)
{
if(!dis_u[to[now][i]])
{
dis_u[to[now][i]]=dis_u[now]+1;
q.push(to[now][i]);
}
}
}
q.push(v[l]);
dis_v[v[l]]=1;
while(!q.empty())
{
int now=q.front();
q.pop();
int len=to[now].size();
for(int i=0;i<len;i++)
{
if(!dis_v[to[now][i]])
{
dis_v[to[now][i]]=dis_v[now]+1;
q.push(to[now][i]);
}
}
}
for(int i=0;i<n;i++)
{
if(dis_u[i]<dis_v[i])
{
que_u[++cnt_u]=i;
}
else
{
que_v[++cnt_v]=i;
}
}
sort(que_u+1,que_u+1+cnt_u,cmp_u);
sort(que_v+1,que_v+1+cnt_v,cmp_v);
l=1,r=cnt_u;
while(l<r)
{
int mid=(l+r)>>1;
for(int i=0;i<num;i++)
{
w[i]=0;
}
for(int i=mid+1;i<=cnt_u;i++)
{
int len=s[que_u[i]].size();
for(int j=0;j<len;j++)
{
w[s[que_u[i]][j]]=1;
}
}
ll value=ask(vector<int>(w,w+num));
if(path==value)
{
r=mid;
}
else
{
l=mid+1;
}
}
S=que_u[l];
l=1,r=cnt_v;
while(l<r)
{
int mid=(l+r)>>1;
for(int i=0;i<num;i++)
{
w[i]=0;
}
for(int i=mid+1;i<=cnt_v;i++)
{
int len=s[que_v[i]].size();
for(int j=0;j<len;j++)
{
w[s[que_v[i]][j]]=1;
}
}
ll value=ask(vector<int>(w,w+num));
if(path==value)
{
r=mid;
}
else
{
l=mid+1;
}
}
T=que_v[l];
answer(S,T);
}

[IOI2018]高速公路收费——二分查找+bfs的更多相关文章

  1. HDU 5652 India and China Origins 二分优化+BFS剪枝

    题目大意:给你一个地图0代表可以通过1代表不可以通过.只要能从第一行走到最后一行,那么中国与印度是可以联通的.现在给你q个点,每年风沙会按顺序侵蚀这个点,使改点不可通过.问几年后中国与印度不连通.若一 ...

  2. jvascript 顺序查找和二分查找法

    第一种:顺序查找法 中心思想:和数组中的值逐个比对! /* * 参数说明: * array:传入数组 * findVal:传入需要查找的数 */ function Orderseach(array,f ...

  3. Java实现的二分查找算法

    二分查找又称折半查找,它是一种效率较高的查找方法. 折半查找的算法思想是将数列按有序化(递增或递减)排列,查找过程中采用跳跃式方式查找,即先以有序数列的中点位置为比较对象,如果要找的元素值小 于该中点 ...

  4. 从一个NOI题目再学习二分查找。

    二分法的基本思路是对一个有序序列(递增递减都可以)查找时,测试一个中间下标处的值,若值比期待值小,则在更大的一侧进行查找(反之亦然),查找时再次二分.这比顺序访问要少很多访问量,效率很高. 设:low ...

  5. java实现二分查找

    /** * 二分查找 * @param a * @param n * @param value * @return * @date 2016-10-8 * @author shaobn */ publ ...

  6. 最新IP地址数据库 二分逼近&二分查找 高效解析800万大数据之区域分布

    最新IP地址数据库  来自 qqzeng.com 利用二分逼近法(bisection method) ,每秒300多万, 比较高效! 原来的顺序查找算法 效率比较低 readonly string i ...

  7. c#-二分查找-算法

    折半搜索,也称二分查找算法.二分搜索,是一种在有序数组中查找某一特定元素的搜索算法. A 搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束: B 如果某一特定元素大于或者小 ...

  8. 【Python】二分查找算法

    二分查找:在一段数字内,找到中间值,判断要找的值和中间值大小的比较.如果中间值大一些,则在中间值的左侧区域继续按照上述方式查找.如果中间值小一些,则在中间值的右侧区域继续按照上述方式查找.直到找到我们 ...

  9. PHP实现文本快速查找 - 二分查找

    PHP实现文本快速查找 - 二分查找法 起因 先说说事情的起因,最近在分析数据时经常遇到一种场景,代码需要频繁的读某一张数据库的表,比如根据地区ID获取地区名称.根据网站分类ID获取分类名称.根据关键 ...

随机推荐

  1. UWP 自定义控件:了解模板化控件 系列文章

    UWP自定义控件的入门文章 [UWP 自定义控件]了解模板化控件(1):基础知识 [UWP 自定义控件]了解模板化控件(2):模仿ContentControl [UWP 自定义控件]了解模板化控件(2 ...

  2. (第十三周)Final阶段成员贡献分

    项目名:食物链教学工具 组名:奋斗吧兄弟 组长:黄兴 组员:李俞寰.杜桥.栾骄阳.王东涵 个人贡献分=基础分+表现分 基础分=5*5*0.5/5=2.5 成员得分如下: 成员 基础分 表现分 个人贡献 ...

  3. JoinPoint

    “JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象. ” JoinPoint适用于注解和Sc ...

  4. 微服务治理平台的RPC方案实现

    导读:本文主要探讨了rpc框架在微服务化中所处的位置,需要解决的问题.同时介绍了用友云微服务治理平台的rpc解决方案,为什么选择该方案.该方案提供的好处是什么.同时也会介绍用友RPC框架的基本结构以及 ...

  5. Django 中的Form表单认证

    一.Form表单   1.1 Form的几个功能 验证用户数据(显示错误信息) 初始化页面显示内容 HTML Form提交保留上次提交数据 生成HTML标签   1.2 创建表单类Form 1. 创建 ...

  6. 在Git中添加一个项目

    首先保证Git服务器正确配置,管理员机器可正常连接并使用Git. 第一步:在服务器上新建一个项目仓库 切换到git用户: a@ubuntu:/home/git$ su - git $ cd /home ...

  7. oracle导出用户下单表或者多表,导入到别的服务器用户下

      导出   exp 用户名/密码 file=存放dmp的名称的目录 statistics=none tables =(表名,表名,表名) exp creditfw/credit file=d:\te ...

  8. Java 获取当前日期的四种方法

    //1 通过Date类来获取当前时间,通过SimpleDateFormat来设置时间格式 SimpleDateFormat dateFormat = new SimpleDateFormat(&quo ...

  9. Azure系列2.1.5 —— BlobOutputStream

    (小弟自学Azure,文中有不正确之处,请路过各位大神指正.) 网上azure的资料较少,尤其是API,全是英文的,中文资料更是少之又少.这次由于公司项目需要使用Azure,所以对Azure的一些学习 ...

  10. [转帖]linux下的CPU、内存、IO、网络的压力测试

    linux下的CPU.内存.IO.网络的压力测试 https://www.cnblogs.com/zhuochong/p/10185881.html 一.对CPU进行简单测试: 1.通过bc命令计算特 ...