诶看到题目我以为是很神很神的数据结构,直接想放弃了
看到题解以后发现题目确实很神,不过并不是很强的数据结构,做法很巧很棒
直接处理升序和降序是没法儿做的
二分答案x,将序列里面的所有元素分成大于x的和小于等于x的,分别用0,1表示,这样区间升序/降序就能转化成为区间赋值,线段树维护即可
代码几乎没难度,可是考场里要想到这个解法可能不容易
#include <iostream>
#include <cstdio>
#define mid ((l+r)>>1)
#define ls l,mid,t<<1
#define rs mid+1,r,t<<1^1
#define N 100050
using namespace std;
struct Node{ int siz,v;}tr[4*N];
struct Monster{ int t,l,r; }Q[N];
int ag[4*N],ll,rr,c,ret;
int a[N],b[N],n,m,p;
Node operator+(Node p1,Node p2) {
Node ret;
ret.siz = p1.siz + p2.siz;
ret.v = p1.v + p2.v;
return ret;
}
inline void push_down(int &t) {
if (ag[t] == -1) return ;
ag[t<<1] = ag[t<<1^1] = ag[t];
tr[t<<1].v = tr[t<<1].siz * ( ag[t] ^ 1 );
tr[t<<1^1].v = tr[t<<1^1].siz * (ag[t] ^ 1);
ag[t] = -1;
}
Node build(int l,int r,int t) {
ag[t] = -1;
return l == r ? tr[t] = (Node){1,b[l]==0} : tr[t] = build(ls) + build(rs);
}
void update(int l,int r,int t) {
if (l > rr || r < ll) return ;
if (l >= ll && r <= rr) {
ag[t] = c;
tr[t].v = tr[t].siz * (c^1);
return ;
}
push_down(t); update(ls); update(rs);
tr[t] = tr[t<<1] + tr[t<<1^1];
}
void query(int l,int r,int t) {
if (l > rr || r < ll) return ;
if (l >= ll && r <= rr) { ret += tr[t].v; return ; }
push_down(t); query(ls); query(rs);
tr[t] = tr[t<<1] + tr[t<<1^1];
}
bool go(int x) {
for (int i=1;i<=n;i++) b[i] = a[i] > x;
build(1,n,1);
for (int _=1;_<=m;_++) {
ll = Q[_].l , rr = Q[_].r , ret = 0;
query(1,n,1);
if (Q[_].t) ret = rr-ll+1 - ret;
ll = Q[_].l , rr = Q[_].l + ret - 1 , c = Q[_].t;
update(1,n,1);
ll = rr+1 , rr = Q[_].r , c = Q[_].t^1;
update(1,n,1);
}
ll = rr = p , ret = 0;
query(1,n,1);
return ret == 1;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
#endif
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",&Q[i].t,&Q[i].l,&Q[i].r);
scanf("%d",&p);
int l = 1 , r = n;
while (l < r) {
int m = (l + r) >> 1;
if (go(m)) r = m; else l = m+1;
}
printf("%d\n",l);
return 0;
}