【BZOJ4552】[Tjoi2016&Heoi2016]排序
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
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3
Sample Output
5
题解:思路非常巧妙,先二分答案,然后将>=mid的位置看成1,其余看成0,然后排序就变成了将段区间的1全都放到左边或右边,这个用线段树很容易搞定。
单调性也十分显然,如果原来的结果是1,那么在增加一个1后,结果不可能变为0;如果原来的结果是0,那么在去掉一个1后,结果不可能变为1。
#include <cstdio> #include <cstring> #include <iostream> #define lson x<<1 #define rson x<<1|1 using namespace std; const int maxn=100010; int n,m,now,pos; int s[maxn<<2],tag[maxn<<2],pa[maxn],pb[maxn],op[maxn],v[maxn]; inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar(); return ret*f; } inline void pushdown(int l,int r,int x) { if(tag[x]!=-1) { int mid=(l+r)>>1; s[lson]=(mid-l+1)*tag[x],s[rson]=(r-mid)*tag[x],tag[lson]=tag[rson]=tag[x]; tag[x]=-1; } } void build(int l,int r,int x) { tag[x]=-1; if(l==r) { s[x]=(v[l]>=now); return ; } int mid=(l+r)>>1; build(l,mid,lson),build(mid+1,r,rson); s[x]=s[lson]+s[rson]; } void updata(int l,int r,int x,int a,int b,int c) { if(a>b) return ; if(a<=l&&r<=b) { s[x]=(r-l+1)*c,tag[x]=c; return ; } pushdown(l,r,x); int mid=(l+r)>>1; if(a<=mid) updata(l,mid,lson,a,b,c); if(b>mid) updata(mid+1,r,rson,a,b,c); s[x]=s[lson]+s[rson]; } int query(int l,int r,int x,int a,int b) { if(a<=l&&r<=b) return s[x]; pushdown(l,r,x); int mid=(l+r)>>1; if(b<=mid) return query(l,mid,lson,a,b); if(a>mid) return query(mid+1,r,rson,a,b); return query(l,mid,lson,a,b)+query(mid+1,r,rson,a,b); } bool check() { build(1,n,1); int i,a; for(i=1;i<=m;i++) { a=query(1,n,1,pa[i],pb[i]); if(op[i]) updata(1,n,1,pa[i],pa[i]+a-1,1),updata(1,n,1,pa[i]+a,pb[i],0); else updata(1,n,1,pa[i],pb[i]-a,0),updata(1,n,1,pb[i]-a+1,pb[i],1); } return query(1,n,1,pos,pos); } int main() { n=rd(),m=rd(); int i,l=1,r=n+1; for(i=1;i<=n;i++) v[i]=rd(); for(i=1;i<=m;i++) op[i]=rd(),pa[i]=rd(),pb[i]=rd(); pos=rd(); while(l<r) { now=(l+r)>>1; if(check()) l=now+1; else r=now; } printf("%d",l-1); return 0; }