[HDU5361]In Touch

122 篇文章 0 订阅

题目

传送门 to HDU

题目概要
在位置 i i i 时,可以走到 y    ( L i ⩽ ∣ y − i ∣ ⩽ R i ) y\;(L_i\leqslant|y-i|\leqslant R_i) y(LiyiRi),代价是 c i c_i ci,求从 1 1 1 出发到每个点的最短路。

数据范围与提示
0 ⩽ L i ⩽ R i ⩽ n ⩽ 2 × 1 0 5 0\leqslant L_i\leqslant R_i\leqslant n\leqslant 2\times 10^5 0LiRin2×105 n ≠ 0 n\ne 0 n=0,显然 1 ⩽ c i ⩽ 1 0 9 1\leqslant c_i\leqslant 10^9 1ci109

思路

简单的方法:线段树优化建图。

如果不那么做呢?考虑像这种题一样,有一个类似线段树懒标记的操作,一点点将标记释放。那么我们的标记相当于:对某个区间内所有的 d i s dis dis 都松弛一下。

当然,其实对 d i s dis dis 的松弛只有这一种。所以我们只考虑这种标记的顺序。显然是先用 t a g tag tag 小的标记来松弛。不过又是具体怎么松弛的呢?显然就是直接找到区间内某个 d i s ⩾ t a g dis\geqslant tag distag 的点,然后更新。

怎么找 d i s dis dis 较大的点呢?带修主席树 并查集。如果我们要用并查集,我们得考虑取出所有 d i s dis dis 较小的点。所以我们有了这样的思路:两个堆,分别维护 t a g tag tag d i s dis dis,每次比较堆顶, d i s dis dis 小就取出来更改并查集,顺便把它可以提供的 t a g tag tag 塞进堆里; t a g tag tag 小就取出来进行修改操作。

直接这么做当然可以了。不过代码还可以更简单一点。考虑 d i s dis dis 那个堆的作用:修改并查集,与提供 t a g tag tag 。第二项可以不必在从堆中取出的时候进行,可以在 d i s dis dis 被更新的时候,立刻加入 t a g tag tag,因为 d i s dis dis 只可能被最小的 t a g tag tag 更新一次。

第一项,修改并查集,也不必在从堆中取出的时候进行。我们不需要显式地修改并查集;在 t a g tag tag 寻找的时候,如果找到了一个 d i s ⩽ t a g dis\leqslant tag distag,就在并查集里修改一下。

再进一步,每个 d i s dis dis 其实就是之前的某个 t a g tag tag 。考虑到 t a g tag tag 是递增的,只需要在每个 d i s dis dis 被更新的时候,直接修改并查集即可。过程类似于:光的反射,每次找最明亮的光,把所有可行的没使用过的镜子找到,记录光的信息,然后将反射光线纳入考虑范围。

所以代码就简单多了。时间复杂度 O ( n log ⁡ n ) \mathcal O(n\log n) O(nlogn)

代码

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long int_;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
inline int readint(){
	int a = 0; char c = getchar(), f = 1;
	for(; c<'0'||c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c&&c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}
inline void writeint(int_ x){
	if(x < 0) putchar('-'), x = -x;
	if(x > 9) writeint(x/10);
	putchar((x-x/10*10)^48);
}
inline int ABS(const int &x){
	return x < 0 ? -x : x;
}

const int_ infty = (1ll<<60)-1;
const int MaxN = 200005;
int_ dis[MaxN]; int c[MaxN];
struct Node{
	int x; Node(int X):x(X){}
	bool operator < (const Node &t) const {
		return dis[x]+c[x] > dis[t.x]+c[t.x];
	}
};
priority_queue<Node> pq;

struct UFS{
	int fa[MaxN];
	void init(int n){
		rep(i,0,n+1) fa[i] = i;
	}
	inline int find(int a){
		if(fa[a] != a)
			fa[a] = find(fa[a]);
		return fa[a];
	}
	void merge(int a,int b){
		fa[find(a)] = find(b);
	}
};
UFS ufs;
int l[MaxN], r[MaxN];
void dijkstra(int n){
	rep(i,1,n) dis[i] = infty;
	dis[1] = 0; pq.push(Node(1));
	ufs.init(n); ufs.merge(1,2);
	while(!pq.empty()){
		int x = pq.top().x; pq.pop();
		for(int i=-1; i<=1; i+=2){
			int L = x+i*l[x], R = x+i*r[x];
			if(i == -1) L ^= R ^= L ^= R;
			if(L > n) continue; // bad
			int p = ufs.find(max(1,L));
			while(p != n+1 && p <= R){
				dis[p] = dis[x]+c[x];
				pq.push(Node(p));
				ufs.merge(p,p+1);
				p = ufs.find(p);
			}
		}
	}
}

int main(){
	for(int T=readint(); T; --T){
		int n = readint();
		rep(i,1,n) l[i] = readint();
		rep(i,1,n) r[i] = readint();
		rep(i,1,n) c[i] = readint();
		dijkstra(n), putchar('0');
		rep(i,2,n){
			if(dis[i] == infty)
				dis[i] = -1;
			putchar(' ');
			writeint(dis[i]);
		}
		putchar('\n');
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值