*题解:P14255 列车(train)

原题链接

解析

注意到对于一个起点站 \(x\),必定有另一个站 \(y > x\) 使得所有以 \(x\) 为起点站,终点站编号小于 \(y\) 的路线均处于停开状态,而所有终点站编号大于等于 \(y\) 的路线均不处于停开状态。

故考虑对于每个站 \(i\),维护 \(a_i\) 表示以 \(i\) 为起点站的非停开线路的最小终点站编号。这样,我们就得到了一个查询和修改均为 \(O(nm)\) 的做法。

考虑优化。对于一次修改操作 \((l,r)\),实际上是让 \(a[l,r]\)\(r + 1\)\(\max\)。观察到 \(a\) 单调不减,故可以上线段树,先线段树上二分找到满足 \(a_i \le r + 1\) 的最小 \(i\),然后对 \(a[l,i]\) 进行区间赋值。

对于一次查询操作,仍然利用单调性,线段树上二分找到使得 \(a_i \le r,i\le l\) 的最大 \(i\),此时最优解为 \(p_r - p_i\)。对于 \([i+1,l]\) 这段区间,最优解为 \(\min(a_j-p_j)\),这个怎么维护呢? push_up 显然;区间推平时,\(a\) 都相等,\(p\) 必定取最大的 \(p\),也就是最右的 \(p\)

时间复杂度 \(O(m \log n)\)

代码

#include <bits/stdc++.h>
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1) | 1)
#define mid ((l + r) >> 1)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 1e5 + 5,M = 100 + 5,mod = 998244353;
int pos[N];
int mn[N << 2],mx[N << 2],tag[N << 2];
int n,m;
void push_up(int p){
	mn[p] = min(mn[ls(p)],mn[rs(p)]);
	mx[p] = max(mx[ls(p)],mx[rs(p)]);
}
void add_tag(int p,int l,int r,int k){
	tag[p] = k;
	mx[p] = k;
	mn[p] = pos[k] - pos[r];
}
void push_down(int p,int l,int r){
	if(tag[p]){
		add_tag(ls(p),l,mid,tag[p]);
		add_tag(rs(p),mid + 1,r,tag[p]);
		tag[p] = 0;
	}
}
void build(int p,int l,int r){
	tag[p] = 0;
	if(l == r){
		mx[p] = l + 1;
		mn[p] = pos[l + 1] - pos[l];
		return;
	}
	build(ls(p),l,mid),build(rs(p),mid + 1,r);
	push_up(p);
}
int query(int p,int l,int r,int L,int R,int k){
	if(l == r) return mx[p] >= k ? l : 2e9;
	push_down(p,l,r);
	if(mx[ls(p)] >= k){
		return query(ls(p),l,mid,L,R,k);
	}else{
		return query(rs(p),mid + 1,r,L,R,k);
	}
}

void modi(int p,int l,int r,int L,int R,int k){
	if(l > R || r < L) return;
	if(l >= L && r <= R){
		add_tag(p,l,r,k);
		return;
	}
	push_down(p,l,r);
	modi(ls(p),l,mid,L,R,k),modi(rs(p),mid + 1,r,L,R,k);
	push_up(p);
}
int ask(int p,int l,int r,int L,int R){
	if(l > R || r < L) return 2e9;
	if(l >= L && r <= R){
		return mn[p];
	}
	push_down(p,l,r);
	return min(ask(ls(p),l,mid,L,R),ask(rs(p),mid + 1,r,L,R));
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T;
	cin>>T;
	while(T--){
		
		cin>>n>>m;
		for(int i=1;i<=n;i++){
			cin>>pos[i];
		}
		pos[n + 1] = 2.1e9;
		build(1,1,n);
		while(m--){
			int o;
			cin>>o;
			if(o == 1){
				int l,r;
				cin>>l>>r;
				int k = query(1,1,n,l,r,r + 1) - 1;
				if(k >= l){
					modi(1,1,n,l,min(k,r),r + 1);
				}
			}else{
				int l,r;
				cin>>l>>r;
				int k = query(1,1,n,l,r,r) - 1;
				k = min(k,n);
				int res = 2e9;
				if(k){
					res = pos[r] - pos[min(l,k)];
				}
				res = min(res,ask(1,1,n,k + 1,l));
				cout<<(res > 1e9 ? -1 : res)<<'\n';
			}
		}
	}
	return 0;
}
posted @ 2025-10-21 07:12  yutar  阅读(5)  评论(0)    收藏  举报