bzoj 4552 排序 线段树+二分 解题报告
来源:互联网 发布:cmf和cms 编辑:程序博客网 时间:2024/06/06 17:22
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
思路
二分答案,判断排序之后的A[q]与mid的关系,
先把原序列中大于mid的数标记为1,否则标记为0。
对01序列进行排序,可以通过线段树完成计数排序,
需要实现区间求和、区间赋值。
最后如果A[q]=1,说明原序列中A[q]>mid ,
否则原序列中A[q] mid 。
求最小的mid满足排序后的序列中A[q] = 0。
复杂度O (nlog^2n)。
代码
#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<cmath>#include<vector>#include<queue>using namespace std;const int N=200000+5; int A[N],v[N];struct data{ int op,x,y;}B[N];int n,M,q,np,rt,cnt[2*N],chi[2*N][2],down[2*N];void build(int &now,int L,int R){ now=++np;cnt[now]=down[now]=0; chi[now][0]=chi[now][1]=0; if (L==R) {cnt[now]=v[L];return ;} int mid=(L+R)>>1; build(chi[now][0],L,mid); build(chi[now][1],mid+1,R); cnt[now]=cnt[chi[now][0]]+cnt[chi[now][1]]; return ;}void pushdown(int now,int L,int R){ int mid=(L+R)/2; if (down[now]) { down[chi[now][0]]=down[chi[now][1]]=down[now]; cnt[chi[now][0]]=(mid-L+1)*(down[now]-1); cnt[chi[now][1]]=(R-mid)*(down[now]-1); } down[now]=0; return ;}void update(int now,int L,int R,int x,int y,int v){ if (x<=L&&R<=y) {down[now]=v+1;cnt[now]=v*(R-L+1);return ;} pushdown(now,L,R); int mid=(L+R)>>1; if (x<=mid) update(chi[now][0],L,mid,x,y,v); if (y>mid) update(chi[now][1],mid+1,R,x,y,v); cnt[now]=cnt[chi[now][0]]+cnt[chi[now][1]]; return;}int query(int now,int L,int R,int x,int y){ if (x<=L&&R<=y) return cnt[now]; pushdown(now,L,R); int mid=(L+R)>>1; int t1=0,t2=0; if (x<=mid) t1=query(chi[now][0],L,mid,x,y); if (y>mid) t2=query(chi[now][1],mid+1,R,x,y); cnt[now]=cnt[chi[now][0]]+cnt[chi[now][1]]; return t1+t2; }bool check(int x){ for (int i=1;i<=n;i++) v[i]=A[i]<=x? 0:1; np=0;int ct; build(rt,1,n); for (int i=1;i<=M;i++) { ct=query(rt,1,n,B[i].x,B[i].y); if (B[i].op==0) { ct=B[i].y-B[i].x+1-ct; if (ct>0) update(rt,1,n,B[i].x,B[i].x+ct-1,0); if (ct<=B[i].y-B[i].x) update(rt,1,n,B[i].x+ct,B[i].y,1); } else { if (ct>0) update(rt,1,n,B[i].x,B[i].x+ct-1,1); if (ct<=B[i].y-B[i].x) update(rt,1,n,B[i].x+ct,B[i].y,0); } } return query(rt,1,n,q,q)==0;}int main(){ scanf("%d%d",&n,&M); for (int i=1;i<=n;i++) scanf("%d",&A[i]); for (int i=1;i<=M;i++) scanf("%d%d%d",&B[i].op,&B[i].x,&B[i].y); scanf("%d",&q); int l=1,r=n,mid,ans; while(l<=r) { mid=(l+r)>>1; if (check(mid)) { r=mid-1;ans=mid;} else l=mid+1; } printf("%d\n",ans); return 0;}
阅读全文
1 0
- bzoj 4552 排序 线段树+二分 解题报告
- [BZOJ]4552 [TJOI2016] 排序 二分 + 线段树
- BZOJ 1012 线段树 解题报告
- bzoj 4552: [Tjoi2016&Heoi2016]排序 二分答案+线段树
- BZOJ 4552 排序(二分 || 线段树合并)
- BZOJ 4552 [Tjoi2016&Heoi2016]排序 线段树+二分
- BZOJ 4552: [Tjoi2016&Heoi2016]排序 二分 线段树
- 【BZOJ】4552 [Tjoi2016&Heoi2016]排序 二分+线段树
- BZOJ 4552: [Tjoi2016&Heoi2016]排序 [二分][线段树]
- BZOJ 1067 [SCOI 2007] 线段树 解题报告
- BZOJ 2733 [HNOI 2012] 线段树合并 解题报告
- BZOJ 2212 [Poi 2011] 线段树合并 解题报告
- 【解题报告】HDU-4614 Vases and Flowers 线段树+二分
- BZOJ 1052 二分答案 解题报告
- 线段树_POJ2528_解题报告
- [ZJOI2016]线段树 解题报告
- BZOJ 4443(SCOI2015)网络流+二分答案 解题报告
- BZOJ 2732 二分+半平面相交 解题报告
- 判断拼接url
- 图书管理系统
- 抢购是如今很常见的一个应用场景,主要需要解决的问题
- RunTimeException-Could not read input channel file descriptors from parcel
- [杂题 单调性] Codeforces #121D. Lucky Segments
- bzoj 4552 排序 线段树+二分 解题报告
- AngularJS 查询 删除 增加 修改
- 解决操作系统连接vpn的问题
- Linux安装JDK和配置环境变量
- Uboot启动参数说明:
- 输入url到页面返回的全过程
- Java代码实现两台电脑之间传文件(1)
- PYTHON神经网络的某些错误
- 腾讯企业邮箱无法登陆