题解:P13614 [IOI 2018] highway 高速公路收费
前言
可能更好的阅读体验
题目传送门
看刘海峰老师的讲座来做的这道题。
前置知识:最短路,二分,广度优先搜索(bfs)。
解析
分三步骤拆解问题:
一
对于
那么,注意到 废话,想找到
二
得到了一条必经边有什么用?
考虑用这条边把原图分为两个子图,使得分别可以求解
假设有一条最短路为
由此,分别跑
三
此时,分别在两个集合中操作。以
时间复杂度
询问次数为三次二分的总和,即
由于
:::info[Code]
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll ask(const vector<int> &w);
void answer(int s, int t);
const int N=90005,M=130005;
const ll inf=1e15;
typedef pair<ll,int> PLI;
bool vis[N];
int pos,m,A,B,h[N],idx=1,e[M<<1],ne[M<<1],val[M<<1],id[N],p[2][N],sz[2];
ll res,d[2][N];
inline void add(int a,int b,int c){e[idx]=b,ne[idx]=h[a],val[idx]=c,h[a]=idx++;}
inline void solve1(int n){
vector <int> w;
int l=0,r=m-1,mid,ans=0;
while (l<=r){
mid=l+r>>1,w.clear();
for (int i=0;i<=mid;i++) w.push_back(1);
for (int i=mid+1;i<=m-1;i++) w.push_back(0);
if (ask(w)!=res) r=mid-1,ans=mid;
else l=mid+1;
}
pos=ans;
}
inline void dijkstra(int n,int s,ll d[]){
priority_queue <PLI,vector <PLI>,greater<PLI>> q;
for (int i=0;i<n;i++) d[i]=inf,vis[i]=0;
d[s]=0,q.push({d[s],s});
while (!q.empty()){
int u=q.top().second;q.pop();
if (vis[u]) continue;
vis[u]=1;
for (int i=h[u];i;i=ne[i]){
int v=e[i],w=val[i];
if (d[v]>d[u]+w)
d[v]=d[u]+w,q.push({d[v],v});
}
}
}
inline void bfs(int s,int o,int p[],int& sz){
queue <int> q;
memset(vis,0,sizeof vis);
q.push(s),vis[s]=1,p[++sz]=s;
while (q.size()){
int u=q.front();q.pop();
for (int i=h[u];i;i=ne[i]){
int v=e[i];
if (id[v]!=o||vis[v]||val[i]==B) continue;
vis[v]=1,p[++sz]=v,q.push(v);
}
}
}
inline void solve2(int n,vector <int> U,vector <int> V){
for (int i=0;i<pos;i++) add(U[i],V[i],B),add(V[i],U[i],B);
for (int i=pos;i<m;i++) add(U[i],V[i],A),add(V[i],U[i],A);
int x=U[pos],y=V[pos];
dijkstra(n,x,d[0]),dijkstra(n,y,d[1]);
for (int i=0;i<n;i++) id[i]=(d[0][i]>d[1][i]);
bfs(x,0,p[0],sz[0]),bfs(y,1,p[1],sz[1]);
}
bool st[N];
inline int solve3(int p[],int sz,vector <int> U,vector <int> V){
int l=1,r=sz,mid,ans=0;
vector <int> W;
for (int i=0;i<pos;i++) W.push_back(1);
for (int i=pos;i<m;i++) W.push_back(0);
while (l<=r){
mid=l+r>>1;
vector <int> w=W;
for (int j=mid;j<=sz;j++) st[p[j]]=1;
for (int j=0;j<m;j++)
if (st[U[j]]||st[V[j]]) w[j]=1;
for (int j=mid;j<=sz;j++) st[p[j]]=0;
if (ask(w)==res) r=mid-1;
else ans=mid,l=mid+1;
}
return p[ans];
}
void find_pair(int n, vector<int> U,vector <int> V,int _A,int _B){
vector <int> w;m=U.size();A=_A,B=_B;
for (int i=0;i<m;i++) w.push_back(0);
res=ask(w),solve1(n),solve2(n,U,V);
int S=solve3(p[0],sz[0],U,V),T=solve3(p[1],sz[1],U,V);
answer(S,T);
}
:::