タイトル
質問の意味:
得られる\(1 \ SIMのn \)今完全な配列、完全なアレイ配列の\(m個\)局所的に、ソートの2種類に分けます。
0,l,r
セクション示す\([L、R] \ ) 数値の昇順にします。
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;
}