其他分享
首页 > 其他分享> > ! TJOI/HEOI2016排序

! 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