set+线段树合并分裂--bzoj4552: [Tjoi2016&Heoi2016]排序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sizeof_you/article/details/85239023

传送门

机房最后一个学习线段树合并的人qwq

题目要求支持区间升序或降序排序,并且单点查询

思路是一开始对每一个点建一个权值线段树,然后排序的话就是把一段权值线段树都合并起来,这样就无所谓顺序了,然后具体操作用 s e t set 什么的维护一下线段树的左右端点就好了

重要的就是线段树合并和分裂了,合并的话就是真正意义上的合并(好像有时候不是直接合并?)把对应的 s i z siz 加起来,分裂根据本题目还要分前 k k 个和后 k k 个,这里可以直接用一个 b o o l bool 记一下,然后看左右儿子的 s i z siz k k 的关系分类讨论一下就好了。

有一些节点删除以后可以垃圾回收,回收的时候注意清空,代码里注释掉的那两行是不能回收的 q w q qwq

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
#define N 100005
#define M 10000005
using namespace std;

template<class T>inline void rd(T &x){
	x=0; short f=1; char c=getchar();
	while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
	while(c<='9' && c>='0') x=x*10+(c^'0'),c=getchar();
	x*=f;
}

int n,m,tot,siz[M],ls[M],rs[M],del[M],top;

inline void insert(int &x,int l,int r,int p){
	if(!x) {if(top) x=del[top--];else x=++tot;}
	++siz[x]; if(l==r) return;
	int mid=l+r>>1;
	if(p<=mid) insert(ls[x],l,mid,p);
	else insert(rs[x],mid+1,r,p);
}

inline int query(int x,int l,int r,int k){//query the kth
	if(l==r) return l;
	int mid=l+r>>1;
	if(siz[ls[x]]>=k) return query(ls[x],l,mid,k);
	else return query(rs[x],mid+1,r,k-siz[ls[x]]);
}

inline void pushup(int x){siz[x]=siz[ls[x]]+siz[rs[x]];}
inline void delet(int x){siz[x]=ls[x]=rs[x]=0;del[++top]=x;}//delete a node

inline int merge(int a,int b,int l,int r){
	if(!a || !b) return a|b;
	siz[a]+=siz[b];
	if(l<r){
		int mid=l+r>>1;
		ls[a]=merge(ls[a],ls[b],l,mid);
		rs[a]=merge(rs[a],rs[b],mid+1,r);
	}
	delet(b);
	return a;
}

inline void split(int x,int l,int r,int k,int &v,bool b){//split k numbers
	if(!v){if(top) v=del[top--]; else v=++tot;}
	if(l==r){
		siz[x]-=k; siz[v]+=k;
		return;
	}
	int mid=l+r>>1;
	if(b){
		int sz=siz[rs[x]];
		if(sz>k) split(rs[x],mid+1,r,k,rs[v],b);
//		else rs[v]=rs[x],delet(rs[x]),rs[x]=0;
		else rs[v]=rs[x],rs[x]=0;
		if(sz<k) split(ls[x],l,mid,k-sz,ls[v],b);
	}
	else{
		int sz=siz[ls[x]];
		if(sz>k) split(ls[x],l,mid,k,ls[v],b);
//		else ls[v]=ls[x],delet(ls[x]),ls[x]=0;
		else ls[v]=ls[x],ls[x]=0;
		if(sz<k) split(rs[x],mid+1,r,k-sz,rs[v],b);
	}
	pushup(x); pushup(v);
}

struct SegT{
	int l,r,t,b;
	SegT(const int ll=0,const int rr=0,const int tt=0,const int bb=0){l=ll,r=rr,t=tt,b=bb;}
	inline bool operator <(const SegT &x) const{
		return r<x.r||(r==x.r&&l<x.l);
	}
};

set<SegT> s;
set<SegT>::iterator it;

inline int solve(int l,int r){
	it=s.lower_bound(SegT(0,l,0,0));
	int rt=0; SegT tmp;
	if(it->l!=l){//split left
		tmp=*it; int a=0;
		split(tmp.t,0,n,l-tmp.l,a,tmp.b);
		s.erase(it);
		s.insert(SegT(tmp.l,l-1,a,tmp.b));
		s.insert(SegT(l,tmp.r,tmp.t,tmp.b));
	}
	it=s.lower_bound(SegT(0,r,0,0));
	if(it->r!=r){//split right
		tmp=*it; int a=0;
		split(tmp.t,0,n,r-tmp.l+1,a,tmp.b);
		s.erase(it);
		s.insert(SegT(tmp.l,r,a,tmp.b));
		s.insert(SegT(r+1,tmp.r,tmp.t,tmp.b));
	}
	while(1){//merge
		it=s.lower_bound(SegT(0,l,0,0));
		if(it==s.end() || r<it->l) break;
		rt=merge(rt,it->t,0,n);
		s.erase(it);
	} return rt;
}

inline int ask(int pos){
	it=s.lower_bound(SegT(0,pos,0,0));
	if(it->b) return query(it->t,0,n,it->r-pos+1);
	else return query(it->t,0,n,pos-it->l+1);
}

int main(){
	rd(n); rd(m); int x,y,z;
	for(int i=1;i<=n;i++){
		rd(x); y=0;
		insert(y,0,n,x);
		s.insert(SegT(i,i,y,0));
	}
	while(m--){
		rd(z); rd(x); rd(y);
		int root=solve(x,y);
		s.insert(SegT(x,y,root,z));
	}
	rd(x);
	printf("%d\n",ask(x));
	return 0;
}

猜你喜欢

转载自blog.csdn.net/sizeof_you/article/details/85239023