CF863E - Turn Off The TV

题意:对于若干个闭区间 \([l_i,r_i]\),它们构成了一个集合 \(\bigcup_{i\le n}{[l_i,r_i]}\),求一个 \(k\),使得 \(\bigcup_{i\le n}{[l_i,r_i]}=\bigcup_{i\le n,i\ne k}{[l_i,r_i]}\)

我们可以区间覆盖,首先我们考虑如果只考虑整点的效果。那么就是离散化,在 \(l\)\(r\) 上进行差分标记,然后前缀和求出每个点被覆盖的次数。如果一个区间覆盖的所有位置都被覆盖 \(2\) 次以上,那么就可以选择这个区间。

但是现在我们需要的是实数轴上的区间,如何处理呢?比如说在整点覆盖中,\([1,2]\)\([3,4]\) 就覆盖了 \(1\sim4\) 的所有点,但在实轴上,\(2.5\) 没有被覆盖。

拆点法

我们可以通过所有坐标集体乘 \(2\)\((a,a+1)\) 这个区间建立一个虚拟的点 \(2a+1\),在离散化的同时将 \(2l\pm 1\)\(2r\pm 1\) 四个点一起离散化进去,从而我们就把实轴区间覆盖问题转化为整点区间覆盖问题。

这里没有使用比较方便的区间差分,而是使用了线段树实现区间加/查询。


#include<bits/stdc++.h>
using namespace std;
#define rd(i,n) for(int i=0;i<n;i++)
#define rp(i,n) for(int i=1;i<=n;i++)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=max(a,b);i>=min(a,b);i--)
#define st string
#define vt vector
#define pb push_back
//#define int long long
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
int q[1200005];
struct node{
	int l,r,s,tg;
}sg[4800005];
inline void init(int i,int l,int r){
	sg[i].l=l,sg[i].r=r,sg[i].s=0;
	if(l==r)return (void)(sg[i].s=q[l]);
	init(i<<1,l,l+r>>1);
	init(i<<1|1,(l+r>>1)+1,r);
	sg[i].s=min(sg[i<<1].s,sg[i<<1|1].s);
}
inline int qry(int i,int l,int r){
	if(sg[i].l>r||sg[i].r<l)return 1e9;
	if(sg[i].l>=l&&sg[i].r<=r)return sg[i].s;
	return min(qry(i<<1,l,r),qry(i<<1|1,l,r));
}
int n,l[200005],r[200005],v[1200005],m;
signed main(){
	cin>>n;
	rp(i,n)cin>>l[i]>>r[i];
	rp(i,n)v[++m]=l[i],v[++m]=r[i],v[++m]=l[i]+1,v[++m]=l[i]-1,v[++m]=r[i]+1,v[++m]=r[i]-1;
	sort(v+1,v+1+m);
	m=unique(v+1,v+1+m)-v-1;
	rp(i,n){
		l[i]=lower_bound(v+1,v+1+m,l[i])-v;
		r[i]=lower_bound(v+1,v+1+m,r[i])-v;
		q[l[i]]++;
		q[r[i]+1]--;
	}
	rp(i,m)q[i]+=q[i-1];
	init(1,1,m);
	rp(i,n){
		if(qry(1,l[i],r[i])>1){
			cout<<i<<endl;
			return 0;
		}
	}cout<<-1<<endl;
	return 0;
}
//Crayan_r

开闭

我们可以将区间转化为左开右闭的形式,在修改的时候减少一位右端点。

这样有什么好处呢?假如我们当前覆盖的区间是 \([l,r]\),则实际上被标记上的整点区间是 \([l-1,r-1]\)

但是我们查询的时候查询的是 \([l,r]\),这样,除非原先的右端点在 \(l+1\) 的位置,否则就不会覆盖到 \(l\),也就解决了中间实数没有覆盖的问题。右边也同理。

#include "bits/stdc++.h"
using namespace std;
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define rer(i,l,u) for(int (i)=(int)(l);(i)<=(int)(u);++(i))
#define reu(i,l,u) for(int (i)=(int)(l);(i)<(int)(u);++(i))
static const int INF = 0x3f3f3f3f; static const long long INFL = 0x3f3f3f3f3f3f3f3fLL;
typedef vector<int> vi; typedef pair<int, int> pii; typedef vector<pair<int, int> > vpii; typedef long long ll;
template<typename T, typename U> static void amin(T &x, U y) { if (y < x) x = y; }
template<typename T, typename U> static void amax(T &x, U y) { if (x < y) x = y; }

int main() {
	int n;
	while (~scanf("%d", &n)) {
		vector<int> L(n);
		vector<int> R(n);
		for (int i = 0; i < n; ++ i)
			scanf("%d%d", &L[i], &R[i]), -- L[i];
		vector<int> values;
		rep(i, n) {
			values.push_back(L[i]);
			values.push_back(R[i]);
		}
		sort(values.begin(), values.end());
		values.erase(unique(values.begin(), values.end()), values.end());
		int X = (int)values.size();
		vector<int> add(X + 1);
		rep(i, n) {
			int l = (int)(lower_bound(values.begin(), values.end(), L[i]) - values.begin());
			int r = (int)(lower_bound(values.begin(), values.end(), R[i]) - values.begin());
			++ add[l], -- add[r];
		}
		rep(i, X)
			add[i + 1] += add[i];
		vector<int> sum(X + 1);
		rep(i, X)
			sum[i + 1] = sum[i] + (add[i] >= 2);
		int ans = -1;
		rep(i, n) {
			int l = (int)(lower_bound(values.begin(), values.end(), L[i]) - values.begin());
			int r = (int)(lower_bound(values.begin(), values.end(), R[i]) - values.begin());
			if (sum[r] - sum[l] == r - l) {
				ans = i;
				break;
			}
		}
		printf("%d\n", ans == -1 ? ans : ans + 1);
	}
	return 0;
}


posted @ 2023-02-22 22:00  jucason_xu  阅读(17)  评论(0编辑  收藏  举报