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
刚开始不是很会做。。想起之前Atcoder有道题:二分一个数x,大于x为1,小于等于为0这道题就可以这么转化因为我们只关心q位置上的数,那就二分x,大于x为1,小于为0排序其实就是将一段覆盖为0或1,另一段相反,那就线段树搞定了处理完后,如果当前这个位置上为0,就说明x>=答案
//MT_LI #include<cmath> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; struct trnode{ int l,r,lc,rc; int lazy,sum[2]; }tr[210000];int trlen; void bt(int l,int r) { int now=++trlen; tr[now].l=l;tr[now].r=r;tr[now].lc=tr[now].rc=-1; tr[now].sum[0]=tr[now].sum[1]=0;tr[now].lazy=-1; if(l<r) { int mid=(l+r)/2; tr[now].lc=trlen+1;bt(l,mid); tr[now].rc=trlen+1;bt(mid+1,r); } } void update(int x) { int lc=tr[x].lc,rc=tr[x].rc; tr[lc].sum[tr[x].lazy]=tr[lc].r-tr[lc].l+1; tr[lc].sum[tr[x].lazy^1]=0; tr[rc].sum[tr[x].lazy]=tr[rc].r-tr[rc].l+1; tr[rc].sum[tr[x].lazy^1]=0; tr[lc].lazy=tr[rc].lazy=tr[x].lazy; tr[x].lazy=-1; } void gai(int now,int p,int c) { if(tr[now].l==tr[now].r){ tr[now].sum[c]=1; tr[now].sum[c^1]=0; return ; } int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy!=-1)update(now); if(p<=mid)gai(lc,p,c); else gai(rc,p,c); for(int i=0;i<=1;i++) tr[now].sum[i]=tr[lc].sum[i]+tr[rc].sum[i]; } void change(int now,int l,int r,int c) { if(l==tr[now].l&&r==tr[now].r) { tr[now].sum[c]=r-l+1; tr[now].sum[c^1]=0;tr[now].lazy=c; return ; } int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy!=-1)update(now); if(mid+1<=l)change(rc,l,r,c); else if(r<=mid)change(lc,l,r,c); else change(lc,l,mid,c),change(rc,mid+1,r,c); for(int i=0;i<=1;i++) tr[now].sum[i]=tr[lc].sum[i]+tr[rc].sum[i]; } int find(int now,int p) { if(tr[now].l==tr[now].r){return tr[now].sum[1]>tr[now].sum[0]?1:0;} int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy!=-1)update(now); if(p<=mid)return find(lc,p); else return find(rc,p); } int findsum(int now,int l,int r,int c) { if(l==tr[now].l&&r==tr[now].r)return tr[now].sum[c]; int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy!=-1)update(now); if(mid+1<=l)return findsum(rc,l,r,c); else if(r<=mid)return findsum(lc,l,r,c); else return findsum(lc,l,mid,c)+findsum(rc,mid+1,r,c); } int n,m,q; int a[110000]; struct node{ int op,l,r; }Q[110000]; bool check(int mid) { for(int i=1;i<=n;i++) { if(a[i]<=mid)gai(1,i,0); else gai(1,i,1); } for(int i=1;i<=m;i++) { int z=findsum(1,Q[i].l,Q[i].r,0),o=findsum(1,Q[i].l,Q[i].r,1); if(Q[i].op==0) { if(z>0)change(1,Q[i].l,Q[i].l+z-1,0); if(o>0)change(1,Q[i].l+z,Q[i].r,1); } else { if(o>0)change(1,Q[i].l,Q[i].l+o-1,1); if(z>0)change(1,Q[i].l+o,Q[i].r,0); } } return find(1,q); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&a[i]); trlen=0;bt(1,n); for(int i=1;i<=m;i++)scanf("%d%d%d",&Q[i].op,&Q[i].l,&Q[i].r); scanf("%d",&q); int ans,l=1,r=n; while(l<=r) { int mid=(l+r)/2; if(check(mid))l=mid+1; else r=mid-1,ans=mid; } printf("%d\n",ans); return 0; }
The deepest love I think,later than apart,I will live as you like