BZOJ4552: [Tjoi2016&Heoi2016]排序

4552: [Tjoi2016&Heoi2016]排序

Time Limit: 60 Sec  Memory Limit: 256 MB
Submit: 2554  Solved: 1302
[Submit][Status][Discuss]

Description

在2016年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题
,需要你来帮助他。这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排
序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q
位置上的数字。

Input

输入数据的第一行为两个整数n和m。n表示序列的长度,m表示局部排序的次数。1 <= n, m <= 10^5第二行为n个整
数,表示1到n的一个全排列。接下来输入m行,每一行有三个整数op, l, r, op为0代表升序排序,op为1代表降序
排序, l, r 表示排序的区间。最后输入一个整数q,q表示排序完之后询问的位置, 1 <= q <= n。1 <= n <= 10^5
,1 <= m <= 10^5
 

Output

 输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第q位置上的数字。

Sample Input

6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3

Sample Output

5

HINT

 

Source

 
[Submit][Status][Discuss]

 

 

题解:线段树合并与分裂模板题???这题有个非常巧妙的二分答案转化为01序列的线段树做法,也相对好写,但多了一层log。然后快一点的做法是先建立N颗权值线段树,动态开点,记录每个区间下节点个数。一段区间排序就是将这段区间合并。但是前后的区间合并会产生交集,从而就需要分裂,就是我们要取出l,r这段区间,在左右两侧的能延伸进来的线段都要分裂。就对于左边来说l所属的那个区间如果左端点小于l那么就要分开,也就是维护一些不相交的线段,且他们的并是1~n,那么之前几个月虽然这类题没碰过但是听到了很多讨论,肯定是用个set啦,就按照右端点排序,二分一下就可以找到一个点所属的线段。然后就像权值线段树那样查找第k个元素就好了。不过因为有递增递减两种序列,那么就是如果是递减就先减右区间,递增先减左区间。以上内容都是我学着这篇代码理解的。http://www.cnblogs.com/Gloid/p/10204585.html

#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define ll long long
using namespace std;
const int maxn=1e5+7;
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,m;
struct node
{
	int l,r,num;
}no[maxn*80];
int state[maxn],root[maxn];
struct seg
{
	int l,r;
	seg(){};
	seg(int _l,int _r){l=_l;r=_r;}
	friend bool operator<(seg a,seg b){return a.r<b.r;}
};
set<seg>st;
int cnt;
void insertt(int &x,int l,int r,int pl)
{
	if(!x)x=++cnt;no[x].num++;
	if(l==r)return;
	int mid=(l+r)>>1;
	if(pl<=mid)insertt(no[x].l,l,mid,pl);
	else insertt(no[x].r,mid+1,r,pl);
}
void split(int &x,int &y,int k,int op)
{
	if(!x)return;
	y=++cnt;no[y].num=no[x].num-k;no[x].num=k;
	if(op==0)
	{
		if(no[no[x].l].num==k){
			no[y].r=no[x].r;no[x].r=0;
			return;
		}
		else if(no[no[x].l].num>k){
			no[y].r=no[x].r;no[x].r=0;
			split(no[x].l,no[y].l,k,op);
		}
		else
		{
			split(no[x].r,no[y].r,k-no[no[x].l].num,op);
		}
	}
	else
	{
		if(no[no[x].r].num==k){
			no[y].l=no[x].l;no[x].l=0;
			return;
		}
		else if(no[no[x].r].num>k){
			no[y].l=no[x].l;no[x].l=0;
			split(no[x].r,no[y].r,k,op);
		}
		else
		{
			split(no[x].l,no[y].l,k-no[no[x].r].num,op);
		}
	}
}
void merge(int &x,int &y,int l,int r)
{
	if(!x||!y){x|=y;return;}
	no[x].num+=no[y].num;
	if(l==r)return;
	int mid=(l+r)>>1;
	merge(no[x].l,no[y].l,l,mid);
	merge(no[x].r,no[y].r,mid+1,r);
}
int query(int x,int l,int r,int pl,int op)
{
	if(l==r)return l;
	int mid=(l+r)>>1;
	//cout<<l<<" "<<r<<endl;
	if(op==0)
	{
		if(no[no[x].l].num>=pl)return query(no[x].l,l,mid,pl,op);
		else return query(no[x].r,mid+1,r,pl-no[no[x].l].num,op);
	}
	else
	{
		if(no[no[x].r].num>=pl)return query(no[x].r,mid+1,r,pl,op);
		else return query(no[x].l,l,mid,pl-no[no[x].r].num,op);

	}
}
set<seg>::iterator it;
int main()
{
	n=read();m=read();
	int tmp;
	for(int i=1;i<=n;i++){
		tmp=read();
		insertt(root[i],1,n,tmp);st.insert(seg(i,i));
	}

	int op,l,r;
	while(m--)
	{
		op=read();l=read();r=read();
		it=st.lower_bound(seg(l,l));
		if((*it).l<l)
		{
			split(root[(*it).l],root[l],l-(*it).l,state[(*it).l]);
			int L=(*it).l,R=(*it).r;
			st.erase(it);
			st.insert(seg(L,l-1));
			st.insert(seg(l,R));state[l]=state[L];
		}
		it=st.lower_bound(seg(r,r));
		if(it!=st.end()&&(*it).l<=r&&(*it).r>r)
		{
			split(root[(*it).l],root[r+1],r-(*it).l+1,state[(*it).l]);
			int L=(*it).l,R=(*it).r;
			st.erase(it);
			st.insert(seg(L,r));st.insert(seg(r+1,R));
			state[r+1]=state[L];
		}
		it=st.lower_bound(seg(l,l));it++;
		while(it!=st.end()&&(*it).r<=r)
		{
			merge(root[l],root[(*it).l],1,n);it++;
		}
		it=st.lower_bound(seg(l,l));
		while(it!=st.end()&&(*it).r<=r){st.erase(it);it=st.lower_bound(seg(l,l));}
		st.insert(seg(l,r));
		state[l]=op;
	}//cout<<cnt<<endl;
	tmp=read();
	it=st.lower_bound(seg(tmp,tmp));
	//cout<<(*it).l<<" "<<(*it).r<<"\n";
	//cout<<state[(*it).l]<<"\n";
	cout<<query(root[(*it).l],1,n,tmp-(*it).l+1,state[(*it).l])<<"\n";

}

  另外我总感觉这数据有点弱。

posted @ 2019-02-22 23:05  Twilight7  阅读(102)  评论(0编辑  收藏  举报