博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ 4552 [Tjoi2016&Heoi2016]排序
阅读量:5216 次
发布时间:2019-06-14

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

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

这道题这是太神了,在zcg学长的推荐下写了这道题,思路就是二分答案和线段树进行验证,对于这颗线段树,每次二分的时候重新建树,每个叶子节点的值为a[pos]是否大于二分出来的那个数,如果大于等于的话为1,否则为0.那么操作0就代表把区间[l,r]里面的1全部放到这个区间的后面,而操作1则是放到前面,用线段树维护sum值再用lazy标记就好了

code:

#include 
#define MAXN 100005using namespace std;int Judge,a[MAXN],n,m,p,Ans; template
inline _t read(){ _t x=0; int f=1; char ch=getchar(); for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')f=-f; for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+(ch^48); return x*f;} struct node{ node *ls,*rs; int sum,set,l,r; inline int __ls(){return ls?ls->sum:0;} inline int __rs(){return rs?rs->sum:0;} void Maintain(){ sum=__ls()+__rs(); } void push_down(){ if(set==-1)return; int m=l+r>>1; if(ls){ ls->set=set; ls->sum=(m-l+1)*set; } if(rs){ rs->set=set; rs->sum=(r-m)*set; } set=-1; } node(){ ls=rs=NULL; sum=0;set=-1; }}*root; void build(node *&o,int l,int r){ if(!o)o=new node(); o->l=l;o->r=r; o->set=-1; if(l==r){ o->sum=(a[l]>=Judge); return; } int m=l+r>>1; build(o->ls,l,m); build(o->rs,m+1,r); o->Maintain();} void Update(node *o,int l,int r,int val){ if(l>r)return; o->push_down(); if(l<=o->l&&o->r<=r){ o->set=val; o->sum=val*(o->r-o->l+1); return; } int m=o->l+o->r>>1; if(l<=m)Update(o->ls,l,r,val); if(m
rs,l,r,val); o->Maintain();} int Query(node *o,int l,int r){ o->push_down(); if(l<=o->l&&o->r<=r)return o->sum; int m=o->l+o->r>>1,ans=0; if(l<=m)ans+=Query(o->ls,l,r); if(m
rs,l,r); return ans;} struct Operation{ int op,l,r; void init(){ op=read
(); l=read
(); r=read
(); }}c[MAXN]; int main(){ n=read
();m=read
(); int maxn = -0x3f3f3f3f; for(int i=1;i<=n;i++)a[i]=read
(),maxn=max(maxn,a[i]); for(int i=1;i<=m;i++)c[i].init(); p=read
(); int l=1,r=maxn; while(l<=r){ Judge=l+r>>1; build(root,1,n); for(int i=1;i<=m;i++){ if(c[i].op==0){ int sum = Query(root,c[i].l,c[i].r); Update(root,c[i].r-sum+1,c[i].r,1); Update(root,c[i].l,c[i].r-sum,0); } else{ int sum = Query(root,c[i].l,c[i].r); Update(root,c[i].l+sum,c[i].r,0); Update(root,c[i].l,c[i].l+sum-1,1); } } int ans = Query(root,p,p); if(ans)Ans=Judge,l=Judge+1; else r=Judge-1; } printf("%d\n",Ans);}

转载于:https://www.cnblogs.com/Cooook/p/7738512.html

你可能感兴趣的文章
Perl IO:随机读写文件
查看>>
Perl IO:IO重定向
查看>>
优化算法系列-模拟退火算法(1)——0-1背包问题
查看>>
转:基于用户投票的排名算法系列
查看>>
WSDL 详解
查看>>
[转]ASP数组全集,多维数组和一维数组
查看>>
git学习
查看>>
C# winform DataGridView 常见属性
查看>>
逻辑运算和while循环.
查看>>
Nhiberate (一)
查看>>
c#后台计算2个日期之间的天数差
查看>>
安卓开发中遇到的小问题
查看>>
ARTS打卡第3周
查看>>
linux后台运行和关闭SSH运行,查看后台任务
查看>>
cookies相关概念
查看>>
CAN总线波形中ACK位电平为什么会偏高?
查看>>
MyBatis课程2
查看>>
桥接模式-Bridge(Java实现)
查看>>
svn客户端清空账号信息的两种方法
查看>>
springboot添加servlet的两种方法
查看>>