luoguP2824 [HEOI2016/TJOI2016]排序(线段树分裂做法)

题意

所谓线段树分裂其实是本题的在线做法。

考虑如果我们有一个已经排好序的区间的权值线段树,那么就可以通过线段树上二分的方法得到第\(k\)个数是谁。
于是用set维护每个升序/降序区间的左右端点以及对应的线段树根节点,区间排序就将区间拆出来,并将对应的线段树也拆出来。

拆线段树就是将前k个值建一棵新树拆出来,用类似fhq treap的方法即可。

code:

#include<bits/stdc++.h>
using namespace std;
#define lc(p) (seg[p].lc)
#define rc(p) (seg[p].rc)
#define sum(p) (seg[p].sum)
const int maxn=1e5+10;
int n,m,Q,tot;
int a[maxn];
queue<int>pool;
struct Seg{int lc,rc,sum;}seg[maxn*20];
struct node
{
	int l,r,root,op;
	bool operator<(const node& x)const{return r==x.r?l<x.l:r<x.r;}
};
set<node>s;
inline int read()
{
	char c=getchar();int res=0,f=1;
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
	return res*f;
}
inline int New()
{
	int x;
	if(!pool.empty())x=pool.front(),pool.pop();
	else x=++tot;
	lc(x)=rc(x)=sum(x)=0;
	return x;
}
void insert(int &p,int l,int r,int pos)
{
	if(!p)p=New();
	sum(p)++;
	if(l==r)return;
	int mid=(l+r)>>1;
	if(pos<=mid)insert(lc(p),l,mid,pos);
	else insert(rc(p),mid+1,r,pos); 
}
void split(int &p,int q,int l,int r,int k)
{
	if(!k)return;
	if(!p)p=New();
	sum(p)+=k,sum(q)-=k;
	if(l==r)return;
	int mid=(l+r)>>1,tmp=sum(lc(q));
	if(k<tmp)split(lc(p),lc(q),l,mid,k);
	else 
	{
		lc(p)=lc(q),lc(q)=0;
		split(rc(p),rc(q),mid+1,r,k-tmp);
	}
}
int merge(int p,int q)
{
	if(!p||!q)return p+q;
	lc(p)=merge(lc(p),lc(q));rc(p)=merge(rc(p),rc(q));
	sum(p)+=sum(q);
	pool.push(q);
	return p;
}
int find(int p,int l,int r,int k)
{
	if(l==r)return l;
	int mid=(l+r)>>1;
	if(sum(lc(p))>=k)return find(lc(p),l,mid,k);
	else return find(rc(p),mid+1,r,k-sum(lc(p)));
}
inline int nodesplit(int l,int r)
{
	set<node>::iterator it=s.lower_bound((node){0,l,0,0});
	if((it->l)!=l)
	{
		node now=*it;
		int p=0;
		s.erase(it);
		if(!now.op)
		{
			split(p,now.root,1,n,l-now.l);
			s.insert((node){now.l,l-1,p,0});
			s.insert((node){l,now.r,now.root,0});
			
		}
		else
		{
			split(p,now.root,1,n,now.r-l+1);
			s.insert((node){now.l,l-1,now.root,1});
			s.insert((node){l,now.r,p,1});
		} 
	}
	it=s.lower_bound((node){0,r,0,0});
	if((it->r)!=r)
	{
		node now=*it;
		int p=0;
		s.erase(it);
		if(!now.op)
		{
			split(p,now.root,1,n,r-now.l+1);
			s.insert((node){now.l,r,p,0});
			s.insert((node){r+1,now.r,now.root,0});
		}
		else
		{
			split(p,now.root,1,n,now.r-r);	
			s.insert((node){now.l,r,now.root,1});
			s.insert((node){r+1,now.r,p,1});
		} 
	}
	int p=0;
	while(2333)
	{
		it=s.lower_bound((node){0,l,0,0});
		if(it==s.end()||(it->l)>r)break;
		node now=*it;s.erase(it);
		p=merge(p,now.root);
	}
	return p;
}
int main()
{
	//freopen("test.in","r",stdin);
	//freopen("test.out","w",stdout);
	n=read(),m=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<=n;i++)
	{
		int p=0;
		insert(p,1,n,a[i]);s.insert((node){i,i,p,0});
	}
	for(int i=1;i<=m;i++)
	{
		int op=read(),l=read(),r=read(),p;
		p=nodesplit(l,r);
		s.insert((node){l,r,p,op});
	}
	Q=read();
	int p=nodesplit(Q,Q);
	printf("%d",find(p,1,n,1));
	return 0;
}
posted @ 2019-12-13 15:31  nofind  阅读(310)  评论(0编辑  收藏  举报