CF1843E Tracking Segments

发布时间 2023-06-28 22:29:54作者: 霜木_Atomic

CF1843E Tracking Segments

VP 的时候本来摆烂了,结果快结束的时候想到了做法(没时间敲了 qwq)。这里提供一种和已有题解不同的思路。

我们发现,对于每个修改,我们可以将该点的值修改为这次修改的时间,未修改的点则赋为 \(n+1\)。这样转化后,区间合法的条件就是区间内小于 \(n+1\) 的值至少要有 $\lfloor \frac{r-l+1}{2} \rfloor+1 $ 个,我们令 \(k = \lfloor \frac{r-l+1}{2} \rfloor+1\),,则最早达到合法条件的时间就是这些值中第 \(k\) 小的。这样一来,我们就可以把问题转化为静态区间第 \(k\) 小,主席树做就行。答案就是所有查询结果中最小值,如果都为 \(n+1\) 则说明无解。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+100;

int n, m;
int root[N], a[N];
int ls[30*N], sum[30*N], rs[30*N],tot;
int read() {
	int x = 0, f = 1;
	char ch = getchar();
	while(ch<'0'||ch>'9') {
		if(ch == '-')f = -1;
		ch = getchar();
	}
	while(ch>='0'&&ch<='9') {
		x = x*10+ch-48;
		ch = getchar();
	}
	return x*f;
}
void change(int &tr, int lst, int l, int r, int p) {
	tr = ++tot;
	sum[tr] = sum[lst]+1;
	if(l == r) return;
	int mid = (l+r)>>1;
	ls[tr] = ls[lst], rs[tr] = rs[lst];
	if(p <= mid) change(ls[tr], ls[lst], l, mid, p);
	else change(rs[tr], rs[lst], mid+1, r, p);
}
int query(int tr, int lst, int l, int r, int kth) {
	if(l == r) return l;
	int mid = (l+r)>>1;
	int tmp = sum[ls[tr]]-sum[ls[lst]];
	if(tmp>=kth) return query(ls[tr], ls[lst], l, mid, kth);
	else return query(rs[tr], rs[lst], mid+1, r, kth-tmp);
}

int T;
struct question{
	int l, r;
}q[N];
int main() {
	T = read() ;
	while(T--){
		
		n = read(), m = read();
		for(int i = 1; i<=m; ++i){
			q[i].l = read();
			q[i].r = read();
		}
		int Q = read();
		for(int i = 1; i<=n; ++i) a[i] = n+1;
		for(int i = 1; i<=Q; ++i){
			int tmp = read();
			a[tmp] = i;
		}
        
		for(int i = 1; i<=n; i++) change(root[i], root[i-1], 1, n+1, a[i]);
		int ans = n+1;
		for(int i = 1; i<=m; i++) {
			int kth = (q[i].r-q[i].l+1)/2+1;
			int tmp = query(root[q[i].r], root[q[i].l-1], 1, n+1, kth);
			if(tmp == n+1) continue;
			else ans = min(ans, tmp);
		}
		if(ans == n+1) puts("-1");
		else printf("%d\n", ans);
		for(int i = 1; i<=tot; ++i){//手动清空防止TLE
			ls[i] = rs[i] = sum[i] =  0;
		}
		for(int i = 1; i<=n; ++i) root[i] = 0;
		tot = 0;
	}

	return 0;
}