BZOJ 4552:[Tjoi2016&Heoi2016]ソートバイナリ・ソート回答セグメントツリー01

タイトル

BZOJ 4552

LUOGU 2824

質問の意味:

得られる\(1 \ SIMのn \)今完全な配列、完全なアレイ配列の\(m個\)局所的に、ソートの2種類に分けます。

  1. 0,l,rセクション示す\([L、R] \ ) 数値の昇順にします。

  2. 1,l,rセクション示す\([L、R] \ ) デジタル降順。

最後に、最初に尋ねる\(Q \)の位置の数字を。

分析

このシーケンスが変換される場合は、単純明快な質問の意味\(01 \)シーケンスは、その後、あなたは、元の配列よりもかなり良く行う必要があります。

あなたが使用することができますので、\(Oを(\ n個のログ) \) アルゴリズム\(01 \)シーケンスの順序、我々は維持するために、ツリーラインを使用します。

クエリインターバル期間\(1 \)と呼ばれる数\(NUM \)が上昇した場合、このセクションでは、あろう([R-NUM + 1 \ \、R]) に変更されている\(1 \) \([Lは、rは、NUM ] \) に変更される)0 \(\しますその後下降\([L、L + numを -1] \) に変更される(1 \)\([R +は、L個のNUM \を \]) に変更される\(0 \) (注:\(NUM = 0 \) 直接\([L、R] \ ) に変更される(0 \)\回避するために、)\(L> Rの\を引き起こし\(RES \) )。

我々は成功した間隔の変更を並べ替えると、クエリの範囲に変換するように。

この質問はそれのために、間違いなくハングアップ、それは半分の答えだろう再びそれを掃引します。

もちろん、この場合には、それだけでオフラインで行うことができます。

バイナリ応答\(MID \) 元のシーケンス\(geqslant Mは\は\)に変更されました\(1 \) 元のシーケンス\(<M \)に変更された(0 \)\、用各操作、\(01 \) それはツリーライン上に言われている配列は、ソート(\ 01 \)ソーティング)、場合\(q個の\)位置または\(1 \) 次に答えが可能です。

そして確立されたバイナリ値場合に限り、位置の値\(\ geqslant M \) ので、もし\は(\チェック)を返し\(trueに\)次に、\(L = MID +。1 \)または\(R&LTを。1-MID = \)

コード

#include<bits/stdc++.h>

const int maxn=1e5+10;

namespace IO
{
    char buf[1<<15],*fs,*ft;
    inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
    template<typename T>inline void read(T &x)
    {
        x=0;
        T f=1, ch=getchar();
        while (!isdigit(ch) && ch^'-') ch=getchar();
        if (ch=='-') f=-1, ch=getchar();
        while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
        x*=f;
    }

    char Out[1<<24],*fe=Out;
    inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
    template<typename T>inline void write(T x,char str)
    {
        if (!x) *fe++=48;
        if (x<0) *fe++='-', x=-x;
        T num=0, ch[20];
        while (x) ch[++num]=x%10+48, x/=10;
        while (num) *fe++=ch[num--];
        *fe++=str;
    }
}

using IO::read;
using IO::write;

int a[maxn];
namespace SGT
{
    int tree[maxn<<2],atag[maxn<<2];
    inline void build(int x,int l,int r,int k)
    {
        if (l==r)
        {
            tree[x]=a[l]>=k;
            atag[x]=0;
            return ;
        }
        int mid=(l+r)>>1;
        build(x<<1,l,mid,k);
        build(x<<1|1,mid+1,r,k);
        tree[x]=tree[x<<1]+tree[x<<1|1];
        atag[x]=0;
    }

    inline void pushdown(int x,int l,int r)
    {
        int mid=(l+r)>>1;
        if (atag[x]==1) tree[x<<1]=mid-l+1, tree[x<<1|1]=r-mid;
        else tree[x<<1]=tree[x<<1|1]=0;
        atag[x<<1]=atag[x<<1|1]=atag[x];
        atag[x]=0;
    }

    inline void Change(int x,int l,int r,int tl,int tr,int k)
    {
        if (tl>r || l>tr) return ;
        if (tl<=l && r<=tr)
        {
            tree[x]=k*(r-l+1);
            atag[x]=k ? 1 : -1;
            return ;
        }
        if (atag[x]) pushdown(x,l,r);
        int mid=(l+r)>>1;
        Change(x<<1,l,mid,tl,tr,k);
        Change(x<<1|1,mid+1,r,tl,tr,k);
        tree[x]=tree[x<<1]+tree[x<<1|1];
    }

    inline int query(int x,int l,int r,int tl,int tr)
    {
        if (tl>r || l>tr) return 0;
        if (tl<=l && r<=tr) return tree[x];
        if (atag[x]) pushdown(x,l,r);
        int mid=(l+r)>>1;
        return query(x<<1,l,mid,tl,tr)+query(x<<1|1,mid+1,r,tl,tr);
    }

    inline int queryPoint(int x,int l,int r,int k)
    {
        if (l==k && k==r) return tree[x];
        if (atag[x]) pushdown(x,l,r);
        int mid=(l+r)>>1;
        if (k<=mid) return queryPoint(x<<1,l,mid,k);
        else return queryPoint(x<<1|1,mid+1,r,k);
    }
}

using SGT::build;
using SGT::query;
using SGT::Change;
using SGT::queryPoint;

int n,m,q;
int opt[maxn],L[maxn],R[maxn];
inline bool check(int x)
{
    build(1,1,n,x);
    for (int i=1; i<=m; ++i)
    {
        int num=query(1,1,n,L[i],R[i]);
        if (!num) { Change(1,1,n,L[i],R[i],0); continue; }//避免出现 L>R 的情况
        if (!opt[i]) Change(1,1,n,R[i]-num+1,R[i],1), Change(1,1,n,L[i],R[i]-num,0);
        else Change(1,1,n,L[i],L[i]+num-1,1), Change(1,1,n,L[i]+num,R[i],0);
    }
    return queryPoint(1,1,n,q);
}

int main()
{
    read(n);read(m);
    for (int i=1; i<=n; ++i) read(a[i]);
    for (int i=1; i<=m; ++i) read(opt[i]),read(L[i]),read(R[i]);
    read(q);
    int l=1, r=n, ans=0;
    while (l<=r)
    {
        int mid=(l+r)>>1;
        if (check(mid)) ans=mid, l=mid+1;
        else r=mid-1;
    }
    write(ans,'\n');
    IO::flush();
    return 0;
}

おすすめ

転載: www.cnblogs.com/G-hsm/p/11482149.html