P7480 Reboot from Blue(最短路,李超树优化dp)
首先,我们发现,直接建图跑最短路肯定不行,因为这样做会有 (O(n^2)) 条边。
那么我们可以考虑减少无用的边。
有这样一个性质:对于一个点,我们发现它只会取到离它左最近或者右最近的比当前点油费小的点。
这是为什么呢?因为相当于如果我们走到这个左端点或者右端点的时候,我们无论是向左还是向右,我们都有更好的选择:在那一个油站加油,再去往下一个目的地。
同样的,为什么是比当前点油价小呢,显而易见,这是因为如果某个地方比当前点油价还要高,那我们还不如就用当前点的油了。
也就是说,这样的话我们只需要把每一个点对于左边和右边各一个点连边即可,这样边数的级别就变成 (O(n)) 了。
最后我们再给终点新建一个对应的结点,跑一遍从 (s) 对应点到 (t) 对应点的最短路即可。
时间复杂度 (O(nlogn)) 。
代码:
#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
x=0;char ch=getchar();bool f=false;
while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return ;
}
template <typename T>
inline void write(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10^48);
return ;
}
#define ll long long
const int N=2e6+5;
const ll INF=2e18+5;
int n,hh=1,tt=0,sta[N],dp[N];
struct node{
ll val;int pos,id;
}a[N];
inline bool cmp(node x,node y){return x.pos<y.pos;}
int head[N],nex[N<<1],to[N<<1],idx,s,t;
ll val[N<<1],dis[N];
bool vis[N];
void add(int u,int v,ll w){
nex[++idx]=head[u];
to[idx]=v;
head[u]=idx;
val[idx]=w;
return ;
}
#define PII pair<ll,int>
priority_queue<PII,vector<PII>,greater<PII> >q;
void dijkstra(){
for(int i=1;i<=n;i++) dis[i]=INF;
dis[s]=0;
q.push(make_pair(0,s));
while(!q.empty()){
PII t=q.top();q.pop();
int x=t.second;ll dist=t.first;
if(vis[x]) continue;
vis[x]=true;
for(int i=head[x];i;i=nex[i]){
int y=to[i];
if(dist+val[i]<dis[y]){
dis[y]=dist+val[i];
q.push(make_pair(dis[y],y));
}
}
}
return ;
}
signed main(){
read(n),read(s),read(t);
for(int i=1;i<=n;i++) read(a[i].val),read(a[i].pos),a[i].id=i;
sort(a+1,a+n+1,cmp);
for(int i=n;i>=1;i--){
while(hh<=tt&&a[i].val<=a[sta[tt]].val) --tt;
dp[i]=sta[tt];
sta[++tt]=i;
}
for(int i=1;i<=n;i++) if(dp[i]) add(i,dp[i],abs(a[i].pos-a[dp[i]].pos)*a[i].val);
tt=0,hh=1;
for(int i=1;i<=n;i++){
while(hh<=tt&&a[i].val<=a[sta[tt]].val) --tt;
dp[i]=sta[tt];
sta[++tt]=i;
}
for(int i=1;i<=n;i++) if(dp[i]) add(i,dp[i],abs(a[i].pos-a[dp[i]].pos)*a[i].val);
for(int i=1;i<=n;i++) if(a[i].pos==s){s=i;break;}
n++;
for(int i=1;i<n;i++) add(i,n,abs(t-a[i].pos)*a[i].val);
dijkstra();
write(dis[n]);
return 0;
}