P7480 Reboot from Blue

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;
}
posted @ 2021-04-16 16:10  __Anchor  阅读(72)  评论(0编辑  收藏  举报