HDU 5361 (优先队列 线段树)

In Touch

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1876    Accepted Submission(s): 510


Problem Description
There are n soda living in a straight line. soda are numbered by  1,2,,n  from left to right. The distance between two adjacent soda is 1 meter. Every soda has a teleporter. The teleporter of  i -th soda can teleport to the soda whose distance between  i -th soda is no less than  li  and no larger than  ri . The cost to use  i -th soda's teleporter is  ci .

The  1 -st soda is their leader and he wants to know the minimum cost needed to reach  i -th soda  (1in)
 

Input
There are multiple test cases. The first line of input contains an integer  T , indicating the number of test cases. For each test case:

The first line contains an integer  n   (1n2×105) , the number of soda. 
The second line contains  n  integers  l1,l2,,ln . The third line contains  n  integers  r1,r2,,rn . The fourth line contains  n  integers  c1,c2,,cn (0lirin,1ci109)
 

Output
For each case, output  n  integers where  i -th integer denotes the minimum cost needed to reach  i -th soda. If  1 -st soda cannot reach  i -the soda, you should just output -1.
 

Sample Input
  
  
1 5 2 0 0 0 1 3 1 1 0 5 1 1 1 1 1
 

Sample Output
  
  
0 2 1 1 -1
Hint
If you need a larger stack size, please use #pragma comment(linker, "/STACK:102400000,102400000") and submit your solution using C++.
 


题意:n个点排在坐标轴1-n的位置,然后告诉你每个点能够访问的距离范围[l,r],

和他访问别的点的花费c[i],求从1出发访问每个点的最小花费。不能访问输出-1.

居然用一种看似会超时的方法过了这题难以置信。

用d[i]表示到i的最小花费,按照dij最短路思想,我们会用d[i]+cost [i]去试着更新

没有取到最小值的点。显然是用最小没有更新过其他点的d[i]+cost[j]去更新,所以

用优先队列维护没有更新过别的节点的节点,key值就是d[i]+cost[j]。然后线段树

维护区间d[i]值的最大,维护最大值的用意就是能够判断区间里面有没有存在能够

更新的节点。然后每个底层的节点最多被访问一次(访问到的时候它就已经取到

最小值了),复杂度看似是O(nlgn),其实可能有极端情况?

反正就这么就过了,貌似跑的还不算太慢。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <map>
#include <queue>
#include <set>
using namespace std;
#define maxn 211111
#define pl c<<1
#define pr (c<<1)|1
#define lson tree[c].l,tree[c].mid,pl
#define rson tree[c].mid+1,tree[c].r,pr
#define INF 1e15

struct node {
	int l, r, mid;
	long long Max;
}tree[maxn<<4];
int l[maxn], r[maxn];
long long cost[maxn], d[maxn];
int n;

void build_tree (int l, int r, int c) {
	tree[c].l = l, tree[c].r = r, tree[c].mid = (l+r)>>1;
	if (l == r) {
		tree[c].Max = d[l];
		return ;
	}
	build_tree (lson);
	build_tree (rson);
	tree[c].Max = max (tree[pl].Max, tree[pr].Max);
}

struct node1 {
	int id;
	long long num;
	bool operator < (const node1 &a) const {
		return num > a.num;
	}
};
priority_queue <node1> gg;

void update (int l, int r, int c, int x, int y, long long val) {
	if (val >= tree[c].Max)
		return ;
	if (l == r) { 
		tree[c].Max = val;
		gg.push ((node1) {l, val+cost[l]});
		d[l] = val;
		return ;
	}
	if (tree[c].mid >= y) {
		if (tree[pl].Max > val)
			update (lson, x, y, val);
	}
	else if (tree[c].mid < x) {
		if (tree[pr].Max > val)
			update (rson, x, y, val);
	}
	else {
		if (tree[pl].Max > val) update (lson, x, tree[c].mid, val);
		if (tree[pr].Max > val) update (rson, tree[c].mid+1, y, val);
	}
	tree[c].Max = max (tree[pl].Max, tree[pr].Max);
}

void solve () {
	for (int i = 2; i <= n; i++) d[i] = INF;
	d[1] = 0;
	build_tree (1, n, 1);
	while (!gg.empty ()) {
		gg.pop ();
	}
	gg.push ((node1) {1, cost[1]});
	while (!gg.empty ()) {
		node1 now = gg.top (); gg.pop ();
		int u = now.id;
		int x = u+l[u], y = u+r[u]; if (x == u) x++; y = min (y, n);
		if (x <= y) { 
			update (1, n, 1, x, y, now.num);
		}

		x = u-r[u], y = u-l[u]; if (y == u) y--; x = max (1, x);
		if (x <= y) {
			update (1, n, 1, x, y, now.num);
		}
	}
	for (int i = 1; i <= n; i++) {
		if (d[i] >= INF) {
			printf ("-1");
		}
		else 
			printf ("%lld", d[i]);
		printf ("%c", (i == n ? '\n' : ' '));
	}
}

int main () {
	int t;
	scanf ("%d", &t);
	while (t--) {
		scanf ("%d", &n);
		for (int i = 1; i <= n; i++) scanf ("%d", &l[i]);
		for (int i = 1; i <= n; i++) scanf ("%d", &r[i]);
		for (int i = 1; i <= n; i++) scanf ("%lld", &cost[i]);
		solve ();
	}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值