[HEOI2016/TJOI2016] 排序

一、题目

点此看题

二、解法

线段树分裂真鸡巴快,就是有点费脑子

首先把原序列看成若干个有序段的排列,那么操作就相当于把边界上的有序段拆分,然后把中间的所有有序段合并起来。具体实现中我们用 \(\tt set\) 来添加断点,用线段树分裂来处理边界上的有序段,然后用线段树合并把区间涉及到的有序段全部合并起来。

时间复杂度简略说明一下,首先和 \(\tt set\) 有关的复杂度显然是 \(O(n\log n)\),考虑线段树的复杂度,单次线段树分裂的复杂度是 \(O(\log n)\),我们可以花费 \(O(\log n)\) 把线段树合并回去,初始时把线段树合一起的复杂度是 \(O(n\log n)\),所以总时间复杂度 \(O((n+q)\log n)\),显然这种方法支持在线询问。

#include <cstdio>
#include <set>
using namespace std;
const int N = 100005;
const int M = 100*N;
#define sit set<int>::iterator
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,cnt,rt[N],o[N],sz[M],ls[M],rs[M];set<int> s;
void add(int &x,int l,int r,int id)
{
	if(!x) x=++cnt;sz[x]++;
	if(l==r) return ;
	int mid=(l+r)>>1;
	if(mid>=id) add(ls[x],l,mid,id);
	else add(rs[x],mid+1,r,id);
}
int merge(int x,int y)
{
	if(!x || !y) return x+y;
	sz[x]+=sz[y];
	ls[x]=merge(ls[x],ls[y]);
	rs[x]=merge(rs[x],rs[y]);
	return x;
}
void split(int &x,int y,int l,int r,int k,int o)
{
	if(sz[y]==k) return ;
	int mid=(l+r)>>1;x=++cnt;
	sz[x]=sz[y]-k;sz[y]=k;
	if(o)//decrease
	{
		if(k<=sz[rs[y]]) 
			split(rs[x],rs[y],mid+1,r,k,o)
			,ls[x]=ls[y],ls[y]=0;
		else
			split(ls[x],ls[y],l,mid,k-sz[rs[y]],o);
	}
	else
	{
		if(k<=sz[ls[y]])
			split(ls[x],ls[y],l,mid,k,o)
			,rs[x]=rs[y],rs[y]=0;
		else
			split(rs[x],rs[y],mid+1,r,k-sz[ls[y]],o);
	}
}
sit fuck(int p)
{
	sit i=s.lower_bound(p);
	if(*i==p) return i;i--;
	split(rt[p],rt[*i],0,n,p-*i,o[p]=o[*i]);
	return s.insert(p).first;
}
int ask(int x,int l,int r)
{
	if(l==r) return l;
	int mid=(l+r)>>1;
	return ls[x]?ask(ls[x],l,mid):ask(rs[x],mid+1,r);
}
signed main()
{
	n=read();m=read();s.insert(n+1);
	for(int i=1;i<=n;i++)
	{
		int x=read();
		s.insert(i),add(rt[i],0,n,x);
	}
	while(m--)
	{
		int op=read(),l=read(),r=read();
		sit il=fuck(l),ir=fuck(r+1);
		for(sit i=++il;i!=ir;i++)
			rt[l]=merge(rt[l],rt[*i]);
		o[l]=op;s.erase(il,ir);
	}
	int p=read();fuck(p);fuck(p+1);
	printf("%d\n",ask(rt[p],0,n));
}
posted @ 2021-09-06 12:11  C202044zxy  阅读(30)  评论(0编辑  收藏  举报