【Tjoi2016&Heoi2016】排序

Description

在2016年,佳媛姐姐喜欢上了数字序列。因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他。这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序,排序分为两种:

1:(0,l,r)表示将区间[l,r]的数字升序排序

2:(1,l,r)表示将区间[l,r]的数字降序排序

最后询问第q位置上的数字。

Solution

直接排序暴力?(竟然可以水80分!)

直接操作显然是不可以的。

我们二分答案,把原序列每个 ai 减去每次二分的 mid ,然后若 aimid 则变为1,反之变为0,这样我们得到了一个01序列,这样我们可以用线段树维护每次部分排序,最后判断q位置上的数值来确定下一次的mid值。

复杂度为 O(mlog2n)

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define N 100001
using namespace std;
int a[N];
int b[N][3];
int c[N];
struct node{
    int _0,_1;
    int lazy;
}tr[N*4];
int n,m;
int Q;
void build(int v,int l,int r)
{
    if(l==r)
    {
        tr[v]._0=tr[v]._1=0;
        if(!c[l]) tr[v]._0=1;
        else tr[v]._1=1;
        tr[v].lazy=-1;
        return;
    }
    int mid=(l+r)/2;
    build(v*2,l,mid);
    build(v*2+1,mid+1,r);
    tr[v]._0=tr[v*2]._0+tr[v*2+1]._0;
    tr[v]._1=tr[v*2]._1+tr[v*2+1]._1;
    tr[v].lazy=-1;
}
void put(int v,int l,int r,int mid)
{
    if(tr[v].lazy<0) return;
    if(tr[v].lazy==0)
    {
        tr[v*2]._0=mid-l+1,tr[v*2+1]._0=r-mid;
        tr[v*2]._1=tr[v*2+1]._1=0;
    }
    else
    {
        tr[v*2]._1=mid-l+1,tr[v*2+1]._1=r-mid;
        tr[v*2]._0=tr[v*2+1]._0=0;
    }
    tr[v*2].lazy=tr[v*2+1].lazy=tr[v].lazy;
    tr[v].lazy=-1;
}
void change(int v,int l,int r,int x,int y,int t)
{
    if(l==x && r==y)
    {
        tr[v].lazy=t;
        if(t==0) tr[v]._0=r-l+1,tr[v]._1=0;
        else tr[v]._1=r-l+1,tr[v]._0=0;
        return;
    }
    int mid=(l+r)/2;
    put(v,l,r,mid);
    if(y<=mid) change(v*2,l,mid,x,y,t);
    else if(x>mid) change(v*2+1,mid+1,r,x,y,t);
    else
    {
        change(v*2,l,mid,x,mid,t);
        change(v*2+1,mid+1,r,mid+1,y,t);
    }
    tr[v]._0=tr[v*2]._0+tr[v*2+1]._0;
    tr[v]._1=tr[v*2]._1+tr[v*2+1]._1;
}
int find(int v,int l,int r,int x,int y,int t)
{
    if(l==x && r==y)
    {
        if(!t) return tr[v]._0;
        else return tr[v]._1;
    }
    int mid=(l+r)/2;
    put(v,l,r,mid);
    if(y<=mid) return find(v*2,l,mid,x,y,t);
    else if(x>mid) return find(v*2+1,mid+1,r,x,y,t);
    else return find(v*2,l,mid,x,mid,t)+find(v*2+1,mid+1,r,mid+1,y,t);
}
int findans(int v,int l,int r,int x)
{
    if(l==r && l==x)
    {
        return tr[v]._0?0:1;
    }
    int mid=(l+r)/2;
    put(v,l,r,mid);
    if(x<=mid) return findans(v*2,l,mid,x);
    else return findans(v*2+1,mid+1,r,x);
}
bool check(int mid)
{
    fo(i,1,n) c[i]=(a[i]>=mid);
    build(1,1,n);
    fo(i,1,m)
    {
        int t=b[i][0],x=b[i][1],y=b[i][2];
        int q=find(1,1,n,x,y,t);
        if(x<=x+q-1) change(1,1,n,x,x+q-1,t);
        if(x+q<=y) change(1,1,n,x+q,y,1-t);
    }
    int z=findans(1,1,n,Q);
    if(z) return true;
    else return false;
}
int main()
{
    freopen("2.in","r",stdin);
    freopen("2.out","w",stdout);
    cin>>n>>m;
    int mmax=0;
    fo(i,1,n)
    scanf("%d",&a[i]);
    fo(i,1,m)
    {
        int t,l,r;
        scanf("%d %d %d",&t,&l,&r);
        b[i][0]=t;
        b[i][1]=l;
        b[i][2]=r;
    }
    cin>>Q;
    int l=1,r=n,ans;
    while(l<r)
    {
        int mid=(l+r)/2;
        if(check(mid)) ans=mid,l=mid+1;
        else r=mid-1;
    }
    if(check(l)) ans=l;
    cout<<ans;
}
posted @ 2016-07-12 19:24  sadstone  阅读(53)  评论(0编辑  收藏  举报