https://www.luogu.org/problemnew/show/P2824node
在2016年,佳媛姐姐喜歡上了數字序列。於是他常常研究關於序列的一些奇奇怪怪的問題,如今他在研究一個難題,須要你來幫助他。這個難題是這樣子的:給出一個1到n的全排列,如今對這個全排列序列進行m次局部排序,排序分爲兩種:1:(0,l,r)表示將區間[l,r]的數字升序排序2:(1,l,r)表示將區間[l,r]的數字降序排序。最後詢問第q位置上的數字。ios
然而我並無寫,口胡一下就是二分最終的那個數字,假設咱們二分的值是$val$,那麼在序列中大於等於$val$咱們當作1,小於$val$的咱們當作0,這樣就是一個01序列了。每次操做咱們就線段樹維護0的個數和1的個數而後區間賦值就是了。最終咱們看一下第q個位置是0仍是1,若是是1就把$val$調大,不然調小。函數
主要講講這個吧spa
考慮咱們一開始對每一個元素建一顆動態開點權值線段樹,由於是1到n的排列咱們都不須要離散化(其實自己是動態開點好像也沒有很大的影響)。這樣咱們就獲得了一個個由一個元素構成的區間,在以後的操做中而後咱們用set維護一下每一個區間的左端點,右端點,這個區間線段樹的根節點和這個區間是單調增的仍是單調減的。code
無論是操做1仍是操做2,咱們就是把[l,r]的全部元素合併到一棵線段樹,惟一麻煩的就是端點l,r多是在當前的某個區間裏面,這樣的話咱們還須要把這個區間給分裂,再把咱們須要的那部分拿出來合併blog
代碼實現是這樣的,注意咱們還要修改一下set排序
set<Dat>::iterator it=s.lower_bound((Dat){0,l,0,0}); if ((*it).l!=l) { Dat t=*it;s.erase(it);int tn=0; if (t.type==0) { Seg::split(1,n,t.nd,tn,l-t.l); s.insert((Dat){t.l,l-1,tn,0}); s.insert((Dat){l,t.r,t.nd,0}); //printf("qq%d %d\n",t.l,l-1); //printf("qq%d %d\n",l,t.r); } else { Seg::split(1,n,t.nd,tn,t.r-l+1); s.insert((Dat){t.l,l-1,t.nd,1}); s.insert((Dat){l,t.r,tn,1}); } } it=s.lower_bound((Dat){0,r,0,0}); if ((*it).r!=r) { Dat t=*it;s.erase(it);int tn=0; if (t.type==0) { Seg::split(1,n,t.nd,tn,r-t.l+1); //printf("qq%d\n",tn); s.insert((Dat){t.l,r,tn,0}); s.insert((Dat){r+1,t.r,t.nd,0}); } else { Seg::split(1,n,t.nd,tn,t.r-r); s.insert((Dat){t.l,r,t.nd,1}); s.insert((Dat){r+1,t.r,tn,1}); } }
it就是咱們當前要分裂的區間,(*it).nd就是這個區間的根節點,l,r是咱們此次操做的區間。對於Dat這個結構體咱們採起右端點優先,左端點次一級的排序。內存
因爲升降序不一樣,咱們要從要分裂的區間的線段樹取出來的部分也不一樣,多是後面的,也多是前面的,這就須要分類討論一下了(不要怕麻煩,懶得話就不要學這種作法)get
還學到了一個回收空間內存的作法,具體時間就是用一個棧保存一下可使用的結點,每次要用結點的時候讓一個元素出棧便可,可見getnode函數string
#include<algorithm> #include<cstring> #include<iostream> #include<cstdio> #include<set> using namespace std; int n,m; namespace Seg { const int N=6e5+15; int lx[N],rx[N],siz[N]; int st[N+10];int top; void init() {for (int i=N-1;i>=1;i--) st[++top]=i;} int getnode() {int t=st[top--];lx[t]=rx[t]=siz[t]=0;return t;} void delnode(int x) {st[++top]=x;} #define mid ((l+r)>>1) void update(int &o,int l,int r,int x) { if (!o) o=getnode(); if (l==r) {siz[o]++;return;} if (x<=mid) update(lx[o],l,mid,x); else update(rx[o],mid+1,r,x); siz[o]=siz[lx[o]]+siz[rx[o]]; } void split(int l,int r,int o,int &x,int k) { if (!k) return; if (!x) x=getnode(); if (l==r) {siz[o]-=k;siz[x]+=k;return;} int t=siz[lx[o]]; if (t>k) split(l,mid,lx[o],lx[x],k); if (t==k) lx[x]=lx[o],lx[o]=0; if (t<k) { lx[x]=lx[o];lx[o]=0; split(mid+1,r,rx[o],rx[x],k-t); } siz[o]=siz[lx[o]]+siz[rx[o]]; siz[x]=siz[lx[x]]+siz[rx[x]]; } int merge(int x,int y) { if (!x||!y) return x|y; lx[x]=merge(lx[x],lx[y]); rx[x]=merge(rx[x],rx[y]); siz[x]+=siz[y]; delnode(y); return x; } int kth(int l,int r,int o,int k) { if (l==r) return l; if (siz[lx[o]]>=k) return kth(l,mid,lx[o],k); else return kth(mid+1,r,rx[o],k-siz[lx[o]]); } } struct Dat { int l,r,nd,type; }; bool operator <(const Dat &a,const Dat &b) { return a.r<b.r||(a.r==b.r&&a.l<b.l); } set <Dat> s; inline int read() { char ch=getchar(); int s=0,f=1; while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();} return s*f; } int split_node(int l,int r) { set<Dat>::iterator it=s.lower_bound((Dat){0,l,0,0}); if ((*it).l!=l) { Dat t=*it;s.erase(it);int tn=0; if (t.type==0) { Seg::split(1,n,t.nd,tn,l-t.l); s.insert((Dat){t.l,l-1,tn,0}); s.insert((Dat){l,t.r,t.nd,0}); //printf("qq%d %d\n",t.l,l-1); //printf("qq%d %d\n",l,t.r); } else { Seg::split(1,n,t.nd,tn,t.r-l+1); s.insert((Dat){t.l,l-1,t.nd,1}); s.insert((Dat){l,t.r,tn,1}); } } it=s.lower_bound((Dat){0,r,0,0}); if ((*it).r!=r) { Dat t=*it;s.erase(it);int tn=0; if (t.type==0) { Seg::split(1,n,t.nd,tn,r-t.l+1); //printf("qq%d\n",tn); s.insert((Dat){t.l,r,tn,0}); s.insert((Dat){r+1,t.r,t.nd,0}); } else { Seg::split(1,n,t.nd,tn,t.r-r); s.insert((Dat){t.l,r,t.nd,1}); s.insert((Dat){r+1,t.r,tn,1}); } } int re=0; while (1) { it=s.lower_bound((Dat){0,l,0,0}); if (it==s.end()||(*it).l>r) break; Dat t=(*it);s.erase(it); re=Seg::merge(re,t.nd); } //printf("%d\n",re); return re; } int main() { Seg::init(); n=read();m=read(); for (int i=1;i<=n;i++) { int t=0; Seg::update(t,1,n,read()); //printf("%d\n",t); s.insert((Dat){i,i,t,0}); } while (m--) { int op=read(),l=read(),r=read(); int t=split_node(l,r); s.insert((Dat){l,r,t,op}); } int q=read(); int t=split_node(q,q); //printf("%d\n",t); printf("%d\n",Seg::kth(1,n,t,1)); return 0; }