icpc2019 香港 H. Hold the Line (离线+线段树+单调队列)

题目链接:https://codeforces.com/gym/102452/problem/H

将所有询问离线下来,按照右端点从小到大排序,每处理一个新询问,就将所有位置小于等于 \(r\) 的士兵加入线段树,线段树每个节点维护的高度在 \([l,r]\) 内的所有节点(位置和插入时间),那么对于当前询问,线段树中所有的点都是小于 \(r\) 的,我们要找到位置大于 \(l\) 并且插入时间在该询问之前的节点。

如果线段树同一个节点上,有士兵位置更靠左(\(x\) 较小)且插入时间更晚,那我们不需要保留该士兵,于是我们维护的就是位置和时间都递增的单调队列,查询是否有合法节点,在该节点的单调队列中二分查找即可。

时间复杂度 \(O(nlogn + mlog^2n)\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 1000010;
const int INF = 1000000007;

int T;
int n, m; 
int tot, b[maxn], ans[maxn];

int c;
struct CH{
	int x, h, t; 
	
	bool operator < (const CH &y) const{
		return x < y.x;
	}
}cha[maxn];

int q;
struct Q{
	int id;
	int l, r, h, t;
	bool operator < (const Q &y) const{
		return r < y.r;
	}
}que[maxn];

struct Node{
	int tail = 0;
	vector<int> q;
	vector<int> ti;
}t[maxn<<2];

void build(int i, int l, int r){
	t[i].tail = 0; t[i].q.clear();
	t[i].ti.clear();
	if(l == r){
		return;
	}
	int mid = (l+r) >> 1;
	build(i<<1, l, mid); build(i<<1|1, mid+1, r);
}

void mdf(int i, int p, int lp, int ti, int l, int r){
	while(t[i].tail > 0 && t[i].ti[t[i].tail-1] > ti) {
		--t[i].tail;
	}
	if(t[i].q.size() == t[i].tail) {
		t[i].q.push_back(lp);
		t[i].ti.push_back(ti);	
		t[i].tail++;
	} else{	
		t[i].q[t[i].tail] = lp;
		t[i].ti[t[i].tail] = ti;
		t[i].tail++;
	}

	if(l == r){
		return;
	}
	int mid = (l+r) >> 1;
	if(p <= mid) mdf(i<<1, p, lp, ti, l, mid);
	else mdf(i<<1|1, p, lp, ti, mid+1, r);
}

bool check(int i, int l, int r, int pos, int ti){
	int L = 0, R = t[i].tail-1;
	while(L <= R){
		int mid = (L + R) >> 1;
		if(t[i].q[mid] >= pos && t[i].ti[mid] <= ti) return true;
		if(t[i].q[mid] < pos){
			L = mid + 1; 
		} else{
			R = mid - 1;
		}
	}
	return false;
}

int qry_l(int i, int l, int r, int pos, int ti, int hei){
	if(l == r){
		return abs(b[hei]-b[l]);
	}
	
	int mid = (l+r) >> 1;
	
	int res = INF;
	if(hei > mid && check(i<<1|1, mid+1, r, pos, ti)) res = qry_l(i<<1|1, mid+1, r, pos, ti, hei);
	if(res != INF) return res;
	if(check(i<<1, l, mid, pos, ti)) res = qry_l(i<<1, l, mid, pos, ti, hei);
	return res;
}

int qry_r(int i, int l, int r, int pos, int ti, int hei){
	if(l == r){
		return abs(b[hei]-b[l]);
	}
	
	int mid = (l+r) >> 1;
	
	int res = INF;
	if(hei <= mid && check(i<<1, l, mid, pos, ti)) res = qry_r(i<<1, l, mid, pos, ti, hei);
	if(res != INF) return res;
	if(check(i<<1|1, mid+1, r, pos, ti)) res = qry_r(i<<1|1, mid+1, r, pos, ti, hei);
	return res;
//	if(hei <= mid && check(i<<1, l, mid, pos, ti)) return qry_r(i<<1, l, mid, pos, ti, hei);
//	else if(check(i<<1|1, mid+1, r, pos, ti)) return qry_r(i<<1|1, mid+1, r, pos, ti, hei);
//	else return INF;
}

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	T = read();
	while(T--){
		tot = 0, c = 0, q = 0;
		n = read(), m = read();
		
		int op, x, h, l, r;
		for(int i = 1 ; i <= m ; ++i){
			op = read();
			if(op == 0){
				x = read(), h = read();
				cha[++c].x = x, cha[c].h = h, cha[c].t = i;
				b[++tot] = h;
			} else{
				l = read(), r = read(), h = read();
				++q;
				que[q].id = q, que[q].l = l, que[q].r = r, que[q].h = h, que[q].t = i;
				b[++tot] = h;
			}
		}
		
		sort(cha+1, cha+1+c);
		sort(que+1, que+1+q); 
		
		sort(b+1, b+1+tot);
		tot = unique(b+1, b+1+tot)-b-1;
		
		for(int i = 1 ; i <= c ; ++i) cha[i].h = lower_bound(b+1, b+1+tot, cha[i].h) - b;
		for(int i = 1 ; i <= q ; ++i) que[i].h = lower_bound(b+1, b+1+tot, que[i].h) - b;
		
		build(1, 1, tot); // may be tle
		
		int cur = 0;
		for(int i = 1 ; i <= q ; ++i){
			while(cur < c && cha[cur+1].x <= que[i].r) {
				mdf(1, cha[cur+1].h, cha[cur+1].x, cha[cur+1].t, 1, tot); //insert the r-th soilder
				++cur;
			}
			
			if(!check(1, 1, tot, que[i].l, que[i].t)) ans[que[i].id] = -1;
			else {
				int res = INF;
				res = min(res, qry_l(1, 1, tot, que[i].l, que[i].t, que[i].h));
				res = min(res, qry_r(1, 1, tot, que[i].l, que[i].t, que[i].h));
				ans[que[i].id] = res; // find the ans
			}
		}
		
		for(int i = 1 ; i <= q ; ++i) printf("%d\n", ans[i]);
	}
	return 0;
}
posted @ 2021-09-24 14:34  Tartarus_li  阅读(76)  评论(0编辑  收藏  举报