博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【bzoj4552/Tjoi2016&Heoi2016】排序——二分+线段树/平衡树+线段树分裂与合并
阅读量:5023 次
发布时间:2019-06-12

本文共 5679 字,大约阅读时间需要 18 分钟。

Description

在2016年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题
,需要你来帮助他。这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排
序分为两种:1:(0,l,r)表示将区间[l,r]的数字升序排序2:(1,l,r)表示将区间[l,r]的数字降序排序最后询问第q
位置上的数字。

Input

输入数据的第一行为两个整数n和m。n表示序列的长度,m表示局部排序的次数。1 <= n, m <= 10^5第二行为n个整
数,表示1到n的一个全排列。接下来输入m行,每一行有三个整数op, l, r, op为0代表升序排序,op为1代表降序
排序, l, r 表示排序的区间。最后输入一个整数q,q表示排序完之后询问的位置, 1 <= q <= n。1 <= n <= 10^5
,1 <= m <= 10^5

Output

 输出数据仅有一行,一个整数,表示按照顺序将全部的部分排序结束后第q位置上的数字。

Sample Input

6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3

Sample Output

5
 

 
这道题有个比较妙的写法就是二分答案+线段树01排序(网上题解一般都这么写),目测1w多ms能过。
当然这种模型其实是线段树的分裂与合并,不过这里只有一次询问,而这种做法可以解决动态查询的情况。
外层的平衡树(这里用set)维护每段序列是在哪棵线段树上,线段树则存这段序列中有哪些值,这样就做到这段序列是有序的。
因为这里有升序和降序两种情况,所以我们可以先全部按照升序来建线段树,同时给线段树打上是升序还是降序的标记。
刚开始每个位置都是一棵线段树,之后每次把要排序的一段区间合并成一棵,表示此区间已有序。
因为要合并的一段区间有可能是一棵线段树的一部分,所以要考虑线段树分裂的操作。
特别的,当要求排序的一段区间完全在一棵线段树内,如果此线段树的升降序与此次要求相同,则不需做任何操作;
否则,需要把线段树最多分裂成左、中、右三棵(ps.如果先分裂左边,要注意分裂完右边要分裂的端点在线段树中的位置可能左移)。
每次排序后都要把不需要的线段树从set中删除,再把新的线段树插入平衡树中。
查询的时候先在set中查出该位置位于哪一棵线段树中,在到那棵线段树中去找就行了(注意此线段树是升序还是降序)。
注意可以垃圾回收的地方:因为涉及到点的删除和增加,因此我们可以开个栈来储存线段树的节点编号,每次从栈顶取元素作为当前节点的编号。
因为叶子节点总数永远为n,所以节点数不会大于nlog(n)。
复杂度:(n+m)*log(n)
在bzoj上不加fread跑了1732ms,说明还是比第一种做法要优很多的。
1 #include
2 #include
3 #include
4 const int N=1e5+10; 5 struct node{ 6 int l,r,id; 7 bool operator <(const node&p)const{
return p.l>l;} 8 }; 9 typedef std::multiset
me; 10 typedef me::iterator IT; 11 int n,m,st[N*20],q,a[N],op,L,R,t=0,L0,R0; 12 me se; 13 struct point{
int l,r,lson,rson,ok,sz;}e[25*N]; 14 int read(){ 15 int ans=0,f=1;char c=getchar(); 16 while(c<'0'||c>'9'){
if(c=='-')f=-1;c=getchar();} 17 while(c>='0'&&c<='9'){ans=ans*10+c-48;c=getchar();} 18 return ans*f; 19 } 20 void erase(int id){e[id].lson=e[id].rson=e[id].sz=e[id].ok=0;st[++t]=id;} 21 void build(int &rt,int l,int r,int x){ 22 rt=st[t--];e[rt].ok=0;e[rt].l=l;e[rt].r=r;e[rt].sz=1;e[rt].lson=e[rt].rson=0; 23 if(l==r)return; 24 int mid=(l+r)>>1; 25 if(mid>=x)build(e[rt].lson,l,mid,x); 26 else build(e[rt].rson,mid+1,r,x); 27 } 28 void spilt(int&rt,int last,int p,int x){ 29 rt=st[t--];e[rt].l=e[last].l;e[rt].r=e[last].r;e[rt].lson=e[rt].rson=0; 30 int ls=e[last].lson,rs=e[last].rson; 31 if(p){ 32 if(ls&&e[ls].sz>x)spilt(e[rt].lson,ls,p,x); 33 else { 34 e[rt].lson=ls;e[last].lson=0; 35 if(rs&&x!=e[ls].sz)spilt(e[rt].rson,rs,p,x-e[ls].sz); 36 } 37 } 38 else{ 39 if(ls&&e[ls].sz+1>=x){ 40 e[rt].rson=rs;e[last].rson=0; 41 if(x!=e[ls].sz+1)spilt(e[rt].lson,ls,p,x); 42 } 43 else if(rs)spilt(e[rt].rson,rs,p,x-e[ls].sz); 44 } 45 int ll=e[rt].lson,rr=e[rt].rson,ss=0; 46 if(ll)ss+=e[ll].sz;if(rr)ss+=e[rr].sz; 47 if(ss)e[rt].sz=ss,e[last].sz-=ss; 48 } 49 void merge(int rt,int rt0){ 50 int ll=0; 51 if(e[rt0].lson) 52 if(!e[rt].lson)e[rt].lson=e[rt0].lson; 53 else merge(e[rt].lson,e[rt0].lson); 54 if(e[rt0].rson) 55 if(!e[rt].rson)e[rt].rson=e[rt0].rson; 56 else merge(e[rt].rson,e[rt0].rson); 57 int l=e[rt].lson,r=e[rt].rson; 58 if(l)ll+=e[l].sz;if(r)ll+=e[r].sz; 59 e[rt].sz=ll; 60 erase(rt0); 61 } 62 int find(int rt,int k){ 63 if(e[rt].l==e[rt].r)return e[rt].l; 64 int l=e[rt].lson,r=e[rt].rson; 65 if(l&&e[l].sz>=k)return find(l,k); 66 else return find(r,k-e[l].sz); 67 } 68 int main(){ 69 n=read();m=read();int mid=(1+n)>>1; 70 for(int i=0;i<=19*N;i++)st[++t]=i; 71 for(int i=1;i<=n;i++){ 72 a[i]=read();int sum=st[t--]; 73 se.insert((node){i,i,sum});e[sum].l=1;e[sum].r=n;e[sum].ok=0;e[sum].lson=e[sum].rson=0;e[sum].sz=1; 74 if(a[i]<=mid)build(e[sum].lson,1,mid,a[i]); 75 else build(e[sum].rson,mid+1,n,a[i]); 76 } 77 while(m--){ 78 node pp;IT it1;bool flag=1; 79 op=read();L=read();R=read();L0=L;R0=R; 80 IT it=se.upper_bound((node){L,0,0}); 81 it--;int rt=it->id,rt0; 82 if(L==R)continue;if(L>R)std::swap(L,R); 83 if(L==it->l&&R==it->r){e[it->id].ok=op;continue;} 84 int p=0;if(e[it->id].ok)p=1,L=it->r-L+1;else L=L-it->l+1; 85 IT it0=se.upper_bound((node){R,0,0}); 86 it0--;rt0=it0->id; 87 if(e[it0->id].ok)R=it0->r-R+1;else R=R-it0->l+1; 88 if(L0>=it->l&&R0<=it->r){ 89 if(op==e[it->id].ok)continue; 90 L=L0-it->l;R=R0-it->l+2;if(e[it->id].ok)L=e[it->id].sz-L+1,R=e[it->id].sz-R+1; 91 if(L0!=it->l)spilt(rt,it->id,!p,L),e[rt].ok=!op,se.insert((node){it->l,L0-1,rt}); 92 if(L
r)spilt(rt0,it->id,p,R),e[rt0].ok=!op,se.insert((node){R0+1,it->r,rt0}); 94 node pp=*it;e[pp.id].ok=op;pp=(node){L0,R0,it->id}; 95 se.erase(it);se.insert(pp); 96 continue; 97 } 98 if(it->l
id,p,L);100 pp=*it;pp.r=L0-1;se.erase(it);101 it=se.insert(pp);102 }103 else flag=0;p=1;if(e[it0->id].ok)p=0;104 if(it0->r>R0){105 spilt(rt0,it0->id,p,R);pp=*it0;it1=--it0;it0++;pp.l=R0+1;se.erase(it0);se.insert(pp);it0=it1;106 }107 else it1=it0,it0--,se.erase(it1);108 merge(rt,rt0);109 while(it0!=se.begin()&&it!=it0){110 it1=it0;111 merge(rt,it1->id);112 it0--;se.erase(it1);113 }114 e[rt].ok=op;if(!flag)se.erase(it);115 se.insert((node){L0,R0,rt});116 117 }118 q=read();119 IT it=se.upper_bound((node){q,0,0});it--;120 q=q-it->l+1;121 if(e[it->id].ok)q=e[it->id].sz-q+1;122 printf("%d",find(it->id,q));123 return 0;124 }
bzoj4552

 

 
 

转载于:https://www.cnblogs.com/JKAI/p/7639538.html

你可能感兴趣的文章
光照问题之常见算法比较(附Python代码)
查看>>
【转】android颜色对应的xml配置值
查看>>
Java加密解密相关
查看>>
LeetCode & Q88-Merge Sorted Array-Easy
查看>>
这个2012不寻常
查看>>
web基础1
查看>>
接口测试框架1
查看>>
primefaces p:tableData 显示 List<List>
查看>>
css如何引入外部字体?
查看>>
ansible之setup、条件判断、tags、循环handlers
查看>>
数据泵如何生成导出文件的DDL脚本
查看>>
Git/Bitbucket Workflow
查看>>
pygame学习资料
查看>>
6.上传前图片预览
查看>>
腾讯云:搭建 Node.js 环境
查看>>
status 返回当前请求的http状态码
查看>>
Docker基本操作
查看>>
向值栈放数据
查看>>
List集合(有序单列集合)
查看>>
初识跨终端Web
查看>>