BZOJ5259 CERC2017 Intrinsic Interval

版权声明:写得不好,转载请通知一声,还请注明出处,感激不尽 https://blog.csdn.net/As_A_Kid/article/details/88626749

Problem

BZOJ

Solution

队长:这不是WC上讲的析合树吗?
我(懵逼):……?


有一个性质,如果有两个连续区间交叉了,那么它们的交集一定也是连续区间。因为如果它不是,那么中间一定是缺了一个元素,而这两个区间不可能同时拥有这个缺少的元素。
那么对于一个询问,包含它的最短的连续区间,必然是从询问的 r r 端点开始,能包含且 l l 最大的区间。

直接做有点无从下手,把连续区间的定义转化一下,相当于是拥有 r l r-l ( x , x + 1 ) (x,x+1) 的数对的区间,不妨记数对个数为 c c

考虑枚举右端点,那么我们就要查询满足 l + c l = r l+c_l=r 的端点,这个怎么维护呢?不难发现这个左边这个值不可能大于 r r ,因此我们对于这个询问只需要支持查 [ 1 , q l ] [1,ql] 中的最大的值和出现位置即可。修改 c c 是一个区间修改,线段树支持。

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

Code

#include <cstdio>
#include <vector>
#include <set>
using namespace std;
typedef long long ll;
const int maxn=100010;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    if(f) x=-x;
}
struct qy{
	int l,r,id;
	bool operator < (const qy &b)const{return l==b.l?id<b.id:l>b.l;}
}tmp,q[maxn];
struct data{
	int mx,pos;
	data(const int _mx=0,const int _pos=0){mx=_mx;pos=_pos;}
	data operator + (const data &b)const{return mx>b.mx?(*this):b;}
}res,t[maxn<<2];
int n,m,a[maxn],app[maxn],ansl[maxn],ansr[maxn];
int add[maxn<<2];
vector<qy> G[maxn];
vector<qy>::iterator itr;
set<qy> s;
void pushdown(int rt)
{
	t[rt<<1].mx+=add[rt];add[rt<<1]+=add[rt];
	t[rt<<1|1].mx+=add[rt];add[rt<<1|1]+=add[rt];
	add[rt]=0;
}
void build(int l,int r,int rt)
{
	if(l==r){t[rt].mx=t[rt].pos=l;return ;}
	int m=(l+r)>>1;
	build(l,m,rt<<1);build(m+1,r,rt<<1|1);
	t[rt]=t[rt<<1]+t[rt<<1|1];
}
void update(int l,int r,int L,int R,int val,int rt)
{
	if(L<=l&&r<=R){t[rt].mx+=val;add[rt]+=val;return ;}
	int m=(l+r)>>1;
	if(add[rt]) pushdown(rt);
	if(L<=m) update(l,m,L,R,val,rt<<1);
	if(m<R) update(m+1,r,L,R,val,rt<<1|1);
	t[rt]=t[rt<<1]+t[rt<<1|1];
}
data query(int l,int r,int L,int R,int rt)
{
	if(L<=l&&r<=R) return t[rt];
	int m=(l+r)>>1;data res;
	if(add[rt]) pushdown(rt);
	if(L<=m) res=res+query(l,m,L,R,rt<<1);
	if(m<R) res=res+query(m+1,r,L,R,rt<<1|1);
	return res;
}
void input()
{
	read(n);
	for(int i=1;i<=n;i++) read(a[i]);
	read(m);
	for(int i=1;i<=m;i++)
	{
		read(q[i].l);read(q[i].r);q[i].id=i;
		G[q[i].r].push_back(q[i]);
	}
}
int main()
{
	input();
	build(1,n,1);
	for(int i=1;i<=n;i++)
	{
		app[a[i]]=i;
		if(a[i]>1&&app[a[i]-1]) update(1,n,1,app[a[i]-1],1,1);
		if(a[i]<n&&app[a[i]+1]) update(1,n,1,app[a[i]+1],1,1);
		for(itr=G[i].begin();itr!=G[i].end();++itr) s.insert(*itr);
		while(s.begin()!=s.end())
		{
			tmp=*s.begin();
			res=query(1,n,1,tmp.l,1);
			if(res.mx<i) break;
			ansl[tmp.id]=res.pos;ansr[tmp.id]=i;
			s.erase(s.begin());
		}
	}
	for(int i=1;i<=m;i++) printf("%d %d\n",ansl[i],ansr[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/As_A_Kid/article/details/88626749