C72 线段树分裂合并+集合维护 P2824 [HEOI2016/TJOI2016] 排序
视频链接:258 线段树分裂合并+集合维护 P2824 [HEOI2016TJOI2016] 排序_哔哩哔哩_bilibili
Luogu P2824 [HEOI2016/TJOI2016] 排序
【总结】C++ 基础数据结构 —— STL之集合(set)用法详解_c++ stl set-CSDN博客
#include <iostream> #include <cstring> #include <algorithm> #include <set> using namespace std; void read(int &x){ //快读 x=0; char c=getchar(); while(!isdigit(c))c=getchar(); while(isdigit(c))x=x*10+c-'0',c=getchar(); } const int N=100005; #define mid ((l+r)>>1) typedef set<int>::iterator it; //set定位器 set<int> st; int n,m,tot,root[N],o[N]; int ls[N*55],rs[N*55],sum[N*55]; //o[p]:记录p位置之后的一段是升序还是降序 //sum[x]:记录区间权值个数之和 void change(int &x,int l,int r,int p){ //点修 x=++tot; sum[x]=1; if(l==r) return; if(p<=mid)change(ls[x],l,mid,p); else change(rs[x],mid+1,r,p); } int query(int x,int l,int r){ //点查 if(l==r) return l; if(ls[x]) return query(ls[x],l,mid); else return query(rs[x],mid+1,r); } void merge(int &x,int y){ //合并 if(!x||!y){x+=y;return;} sum[x]+=sum[y]; merge(ls[x],ls[y]); merge(rs[x],rs[y]); } void split(int x,int &y,int k,int o){ //分裂 //将x从k处斩断,一段归x,另一段归y if(sum[x]==k) return; y=++tot; sum[y]=sum[x]-k; sum[x]=k; if(o==0){ //升序,前k小归x if(k<=sum[ls[x]]) split(ls[x],ls[y],k,o),swap(rs[x],rs[y]); else split(rs[x],rs[y],k-sum[ls[x]],o); } else{ //降序,后k大归x if(k<=sum[rs[x]]) split(rs[x],rs[y],k,o),swap(ls[x],ls[y]); else split(ls[x],ls[y],k-sum[rs[x]],o); } } it SPL(int p){ //从p处分裂 it i=st.lower_bound(p); //p在集合中的位置 if(*i==p) return i; else i--; //i-1即p所在线段树的版本 split(root[*i],root[p],p-*i,o[p]=o[*i]); return st.insert(p).first; //集合插入p并返回其位置 } int main(){ read(n),read(m); int x,op,l,r,q; for(int i=1;i<=n;++i){ read(x),change(root[i],1,n,x); //n颗线段树 st.insert(i); //下标插入集合 } while(m--){ read(op),read(l),read(r); it a=SPL(l), b=SPL(r+1); //分裂成4段 for(it i=++a;i!=b;++i) merge(root[l],root[*i]); //合并中间段 o[l]=op; //记录l位置之后的一段是升序还是降序 st.erase(a,b); //删除集合[l+1,r]段 } read(q); SPL(q); SPL(q+1); //把q线段树变成链 printf("%d\n",query(root[q],1,n)); }