[洛谷P7480] Reboot from Blue

前言

你老惦记你那 \(O(n)\) 的贪心干啥?

题目

洛谷

讲解

首先我们有一个很明显的结论:选择加油的加油站的油价一定单调不增。

所以我们对于每个加油站,将它向它前后第一个油价不高于它的加油站连边,然后跑最短路即可。

当然终点的油价要赋为最小值。

连边操作可以用单调栈执行。

代码

//12252024832524
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define TT template<typename T>
using namespace std; 

typedef long long LL;
const int MAXN = 100005;
const LL INF = (1ll << 60);
int n,S,T,IDS,IDT;
int q[MAXN],now;

LL Read()
{
	LL x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-') f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}

struct node
{
	int c,x;
	bool operator < (const node &px) const{
		return x < px.x;
	}
}s[MAXN];
int head[MAXN],tot;
struct edge
{
	int v,nxt;LL w;
}e[MAXN << 1];
void Add_Edge(int x,int y,LL z)
{
	e[++tot].v = y;
	e[tot].w = z;
	e[tot].nxt = head[x];
	head[x] = tot;
}

struct dij
{
	int x; LL w;
	dij(){}	
	dij(int x1,LL w1){
		x = x1;
		w = w1;
	}	
	bool operator < (const dij &px)const{
		return w > px.w;
	}
};
LL dis[MAXN];
void bfs()
{
	for(int i = 1;i <= n;++ i) dis[i] = INF;
	priority_queue<dij> q;
	q.push(dij(IDS,dis[IDS] = 0));
	while(!q.empty())
	{
		dij p = q.top(); q.pop();
		if(p.w > dis[p.x]) continue;
		if(p.x == IDT) break;
		for(int i = head[p.x]; i ;i = e[i].nxt)
			if(p.w + e[i].w < dis[e[i].v])
				q.push(dij(e[i].v,dis[e[i].v] = p.w + e[i].w));
	}
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read(); S = Read(); T = Read();
	for(int i = 1;i <= n;++ i) 
	{
		s[i].c = Read(),s[i].x = Read();
		if(s[i].x == T) IDT = 1,s[i].c = 0;
	}
	if(!IDT) s[++n].c = 0,s[n].x = T;
	sort(s+1,s+n+1);
	now = 0;
	for(int i = 1;i <= n;++ i)
	{
		if(s[i].x == S) IDS = i;
		if(s[i].x == T) IDT = i;
		while(now >= 1 && s[i].c < s[q[now]].c) now--;
		if(now) Add_Edge(i,q[now],1ll * Abs(s[i].x - s[q[now]].x) * s[i].c);
		q[++now] = i;
	}
	now = 0;
	for(int i = n;i >= 1;-- i)
	{
		while(now >= 1 && s[i].c < s[q[now]].c) now--;
		if(now) Add_Edge(i,q[now],1ll * Abs(s[i].x - s[q[now]].x) * s[i].c);
		q[++now] = i;
	}
	bfs();
	Put(dis[IDT]);
	return 0;
}
posted @ 2021-04-19 15:33  皮皮刘  阅读(59)  评论(0编辑  收藏  举报