[HEOI2016]排序

题目描述

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

输入输出格式

输入格式:

输入数据的第一行为两个整数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

输出格式:

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

输入输出样例

输入样例#1: 
6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3
输出样例#1: 
5
二分一个答案mid
然后用线段树
维护每一位是否大于mid,大于为1,小于为0
最后如果第q位为1,那么说明答案大于mid
至于两个操作,可以简单的用线段树实现
对于1操作:
首先求出区间内1的数量cnt1,0的数量cnt2
按升序排序显然就是把所有1放到区间右边,0放左边
也就是update(l,l+cnt2-1,0),update(l+cnt2,r,1)
2操作类推
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 using namespace std;
  6 struct Node
  7 {
  8   int opt,l,r;
  9 }ask[100001];
 10 int c[400001],lazy[400001],n,m,q,a[100001];
 11 void pushup(int rt)
 12 {
 13   c[rt]=c[rt*2]+c[rt*2+1];
 14 }
 15 void build(int rt,int l,int r,int x)
 16 {
 17   if (l==r)
 18     {
 19       c[rt]=(a[l]>=x);
 20       return;
 21     }
 22   int mid=(l+r)/2;
 23   build(rt*2,l,mid,x);
 24   build(rt*2+1,mid+1,r,x);
 25   pushup(rt);
 26 }
 27 void pushdown(int rt,int l,int r,int mid)
 28 {
 29   if (lazy[rt]==0)
 30     {
 31       lazy[rt*2]=0;
 32       lazy[rt*2+1]=0;
 33       c[rt*2]=0;
 34       c[rt*2+1]=0;
 35       lazy[rt]=-1;
 36     }
 37   if (lazy[rt]==1)
 38     {
 39       lazy[rt*2]=1;
 40       lazy[rt*2+1]=1;
 41       c[rt*2]=mid-l+1;
 42       c[rt*2+1]=r-mid;
 43       lazy[rt]=-1;
 44     }
 45 }
 46 void update(int rt,int l,int r,int L,int R,int d)
 47 {
 48   if (L>R) return ;
 49   if (l>=L&&r<=R)
 50     {
 51       if (d==0) c[rt]=0,lazy[rt]=0;
 52       else c[rt]=r-l+1,lazy[rt]=1;
 53       return;
 54     }
 55   int mid=(l+r)/2;
 56   pushdown(rt,l,r,mid);
 57   if (L<=mid) update(rt*2,l,mid,L,R,d);
 58   if (R>mid) update(rt*2+1,mid+1,r,L,R,d);
 59   pushup(rt);
 60 }
 61 int query(int rt,int l,int r,int L,int R)
 62 {
 63   if (l>=L&&r<=R)
 64     {
 65       return c[rt];
 66     }
 67   int mid=(l+r)/2;
 68   pushdown(rt,l,r,mid);
 69   int s=0;
 70   if (L<=mid) s+=query(rt*2,l,mid,L,R);
 71   if (R>mid) s+=query(rt*2+1,mid+1,r,L,R);
 72   pushup(rt);
 73   return s;
 74 }
 75 bool check(int mid)
 76 {int i;
 77   memset(c,0,sizeof(c));
 78   memset(lazy,-1,sizeof(lazy));
 79   build(1,1,n,mid);
 80   for (i=1;i<=m;i++)
 81     {
 82       int l=ask[i].l,r=ask[i].r;
 83       int cnt1=query(1,1,n,l,r);
 84       int cnt2=r-l+1-cnt1;
 85       if (ask[i].opt==0)
 86     {
 87       update(1,1,n,l,l+cnt2-1,0);
 88       update(1,1,n,l+cnt2,r,1);
 89     }
 90       else 
 91     {
 92       update(1,1,n,l,l+cnt1-1,1);
 93       update(1,1,n,l+cnt1,r,0);
 94     }
 95     }
 96   return query(1,1,n,q,q);
 97 }
 98 int main()
 99 {int i;
100   cin>>n>>m;
101   for (i=1;i<=n;i++)
102     scanf("%d",&a[i]);
103   for (i=1;i<=m;i++)
104       scanf("%d%d%d",&ask[i].opt,&ask[i].l,&ask[i].r);
105   cin>>q;
106   int l=1,r=n,ans;
107   while (l<=r)
108     {
109       int mid=(l+r)/2;
110       if (check(mid)) ans=mid,l=mid+1;
111       else r=mid-1;
112     }
113   cout<<ans;
114 }

 

posted @ 2017-10-26 08:01  Z-Y-Y-S  阅读(268)  评论(0编辑  收藏  举报