您的位置:首页 > 其它

【bzoj4552】【Tjoi2016&Heoi2016】【排序】【线段树】

2016-05-17 09:46 435 查看

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

题解:

首先二分答案。

那么只用判断这个数是否合法即可。

设这个数为x

那么可以把这个序列中比x大的数记为1,比x小的数记为-1,和x相等的数记为0.

最后只用判断q位置上的数是不是0即可.

维护一下序列中-1,0,1的个数,那显然操作可以用线段树处理.

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 100010
using namespace std;
int a
,ans,n,l,r,q,m,v
,p[N<<2],sum;
struct seg{int s0,s1,s2;}t[N<<2];
struct use{int k,l,r;}c
;
seg update(seg a,seg b){
seg c;
c.s0=a.s0+b.s0;
c.s1=a.s1+b.s1;
c.s2=a.s2+b.s2;
return c;
}
void build(int k,int l,int r){
int mid=(l+r)>>1;
if (l==r){
if (v[l]==0) t[k].s0++;
if (v[l]==1) t[k].s1++;
if (v[l]==2) t[k].s2++;
return;
}
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
t[k]=update(t[k<<1],t[k<<1|1]);
}
void paint(int k,int l,int r,int v){
if (v==0){t[k].s0=r-l+1;t[k].s1=t[k].s2=0;}
if (v==1){t[k].s1=r-l+1;t[k].s0=t[k].s2=0;}
if (v==2){t[k].s2=r-l+1;t[k].s0=t[k].s1=0;}
p[k]=v;
}
void pushdown(int k,int l,int r){
int mid=(l+r)>>1;
paint(k<<1,l,mid,p[k]);
paint(k<<1|1,mid+1,r,p[k]);
p[k]=-1;
}
seg query(int k,int l,int r,int ll,int rr){
int mid=(l+r)>>1;
if (ll==l&&r==rr){return t[k];}
if (p[k]!=-1) pushdown(k,l,r);
if (rr<=mid) return query(k<<1,l,mid,ll,rr);
else if (mid<ll) return query(k<<1|1,mid+1,r,ll,rr);
else return update(query(k<<1,l,mid,ll,mid),query(k<<1|1,mid+1,r,mid+1,rr));
}
void change(int k,int l,int r,int ll,int rr,int v){
int mid=(l+r)>>1;
if (ll<=l&&r<=rr){paint(k,l,r,v);return;}
if (p[k]!=-1) pushdown(k,l,r);
if (ll<=mid) change(k<<1,l,mid,ll,rr,v);
if (mid<rr) change(k<<1|1,mid+1,r,ll,rr,v);
t[k]=update(t[k<<1],t[k<<1|1]);
}
int judge(int x){
for (int i=1;i<=n;i++)
if (a[i]<x) v[i]=0;
else if (a[i]==x) v[i]=1;
else v[i]=2;
for (int i=1;i<=(n<<2);i++)
t[i].s0=t[i].s1=t[i].s2=0,p[i]=-1;
build(1,1,n);
for (int i=1;i<=m;i++){
seg tt=query(1,1,n,c[i].l,c[i].r);
//cout<<tt.s0<<' '<<tt.s1<<' '<<tt.s2<<endl;
if (c[i].k==0){
int a=c[i].l+tt.s0-1,b=a+tt.s1;
if (tt.s0) change(1,1,n,c[i].l,a,0);
//cout<<a+1<<' '<<b<<endl;
if (tt.s1) change(1,1,n,a+1,b,1);
if (tt.s2) change(1,1,n,b+1,c[i].r,2);
}
else{
int a=c[i].l+tt.s2-1,b=a+tt.s1;
if (tt.s2) change(1,1,n,c[i].l,a,2);
if (tt.s1) change(1,1,n,a+1,b,1);
if (tt.s0) change(1,1,n,b+1,c[i].r,0);
}
}
seg tt=query(1,1,n,q,q);
if (tt.s0) return 0;
if (tt.s1) return 1;
if (tt.s2) return 2;
}
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",&c[i].k,&c[i].l,&c[i].r);
scanf("%d",&q);l=1;r=n;
//cout<<judge(5)<<endl;
while (l<=r){
//cout<<l<<' '<<r<<endl;
int mid=(l+r)>>1;
int t=judge(mid);
if (t==2) l=mid+1;
else if (t==1) {ans=mid;break;}
else r=mid-1;
}
cout<<ans<<endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: