Loading

【题解】[CCO2020] Interval Collection

支持向集合中加入或删除一格区间,并支持询问,求出一个子集,在满足最大公共子区间最小的前提下,最小公共超区间的最小值。最小公共超区间指包含集合中所有区间的最小的区间。

首先选取的集合只包含两个区间。

分开讨论,如果所有区间的最大公共子区间不为空,那么一定有一个区间卡在右端点,另一个卡在左端点,只用选这两个即可。

否则一定存在两个区间没有交集,多选一个只会使答案更劣。

这提示我们对于答案也可以这样分开讨论。

如果所有区间的最大公共子区间不为空,我们令这个子区间为 \([l,r]\) 。那么我们选取的两个区间一定是左端点为 \(l\) 中右端点最小的,和右端点为 \(r\) 中左端点最大的。

否则一定存在一个位置 \(p\)\([1,p]\) 中有完整区间,\([p,10^6]\) 中有完整区间。

那么我们可以枚举这个 \(p\) ,然后查询左边左端点的最大值,和右边左端点的最小值,单次 \(\mathcal{O}(N)\)

但是这种方法不好扩展,我们考虑枚举 \(p\le q\) 的二元组 \((p,q)\) ,然后查询右端点为 \(p\) 的左端点最大值,和左端点为 \(q\) 的右端点最小值。

可以直接 \(\mathcal{O}(N^2)\) 枚举,但这种类似二维数点的问题可以直接分治做到 \(\mathcal{O}(N\log N)\)

而我们知道线段树的结构非常类似分治树的结构,所以我们用线段树模拟分治树,一次插入/删除相当于两个单点修改,查询就是线段树根节点的答案。

时间复杂度 \(\mathcal{O}(N+Q\log N)\)

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define pre(i,a,b) for(int i=a;i>=b;i--)
#define N 1000005
#define inf 0x3f3f3f3f
using namespace std;
multiset<int>p,q,u[N],v[N];
struct node{int l,r,mxl,mnr,sum;}a[N<<2];
#define L a[x].l
#define R a[x].r
#define ls (x<<1)
#define rs (ls|1)
void build(int x,int l,int r){
	L=l;R=r;a[x].mxl=-inf,a[x].mnr=a[x].sum=inf;
	if(l==r)return;
	int mid=(l+r)>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
}
void modify(int x,int pos){
	if(L==R){
		if(u[L].size())a[x].mnr=*u[L].begin();else a[x].mnr=inf;
		if(v[L].size())a[x].mxl=*v[L].rbegin();else a[x].mxl=-inf;
		a[x].sum=a[x].mnr-a[x].mxl;
		//cout<<"ss "<<x<<" "<<L<<" "<<R<<" "<<pos<<" "<<a[x].sum<<" "<<a[x].mxl<<" "<<a[x].mnr<<endl;
		return;
	}
	int mid=(L+R)>>1;
	if(mid>=pos)modify(ls,pos);
	else modify(rs,pos);
	a[x].mxl=max(a[ls].mxl,a[rs].mxl);
	a[x].mnr=min(a[ls].mnr,a[rs].mnr);
	a[x].sum=min(min(a[ls].sum,a[rs].sum),a[rs].mnr-a[ls].mxl);
	//cout<<"ss "<<x<<" "<<L<<" "<<R<<" "<<pos<<" "<<a[x].sum<<" "<<a[x].mxl<<" "<<a[x].mnr<<endl;
}
int main(){
	build(1,1,N-5);int T;scanf("%d",&T);
	char op[2];int l,r; 
	while(T--){
		scanf("%s%d%d",op,&l,&r);
		if(*op=='A'){
			p.insert(l);q.insert(r);
			u[l].insert(r);v[r].insert(l);
			modify(1,l);modify(1,r);
		}
		else{
			p.erase(p.find(l));q.erase(q.find(r));
			u[l].erase(u[l].find(r));v[r].erase(v[r].find(l));
			modify(1,l);modify(1,r);
		}
		if(*p.rbegin()<*q.begin()){
			int l=*p.rbegin(),r=*q.begin();
			printf("%d\n",*u[l].begin()-*v[r].rbegin());
		}
		else printf("%d\n",a[1].sum);
	}
	return 0;
}
posted @ 2021-06-08 14:37  7KByte  阅读(115)  评论(0编辑  收藏  举报