! TJOI/HEOI2016排序
作者:互联网
只用询问一个地方的值,考虑二分,把大于mid的全变1,否则为0,这样就变成01序列排序,一次\(log\),用线段树辅助,时间复杂度\(O(nlog^2n)\)
线段树分裂
类似非旋treap
建立权值线段树,把有序的用用一个线段树表示,并把所有线段树初始节点插入set,每次修改就把修改区间split出来,记录其排序方式
注:set.insert()返回一个pair,first->插入位置,second->是否成功插入
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=1e5+4,M=6e6;
set<int>t;
int tot,rt[N],lc[M],rc[M],s[M],o[M];
void insert(int &p,int l,int r,int k){
s[p=++tot]=1;
if(l==r)return;
int mid=l+r>>1;
if(k<=mid)insert(lc[p],l,mid,k);
else insert(rc[p],mid+1,r,k);
}
int query(int p,int l,int r){
if(l==r)return l;
int mid=l+r>>1;
if(lc[p])return query(lc[p],l,mid);
else return query(rc[p],mid+1,r);
}
void merge(int &x,int y){
if(!x||!y){x|=y;return;}
s[x]+=s[y];
merge(lc[x],lc[y]);
merge(rc[x],rc[y]);
}
void spl(int &x,int y,int k,int o){
if(s[y]==k)return;
s[x=++tot]=s[y]-k;s[y]=k;
if(o){
if(k<=s[rc[y]]){spl(rc[x],rc[y],k,o);lc[x]=lc[y];lc[y]=0;}
else spl(lc[x],lc[y],k-s[rc[y]],o);
}
else{
if(k<=s[lc[y]]){spl(lc[x],lc[y],k,o);rc[x]=rc[y];rc[y]=0;}
else spl(rc[x],rc[y],k-s[lc[y]],o);
}
}
#define it set<int>::iterator
inline it split(int p){
auto i=t.lower_bound(p);
if(*i==p)return i;
--i;spl(rt[p],rt[*i],p-*i,o[p]=o[*i]);
return t.insert(p).first;//
}
int n,m;
int main(){
n=read();m=read();
t.insert(n+1);
for(int i=1;i<=n;i++){
insert(rt[i],0,n,read());
t.insert(i);
}
while(m--){
int op=read(),l=read(),r=read();
auto il=split(l),ir=split(r+1);
for(auto i=++il;i!=ir;i++)merge(rt[l],rt[*i]);
o[l]=op;t.erase(il,ir);
}
int q=read();
split(q);split(q+1);
cout<<query(rt[q],0,n);
return (0-0);
}
标签:return,lc,int,TJOI,mid,HEOI2016,rc,排序,线段 来源: https://www.cnblogs.com/aurora2004/p/12737733.html