题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4552
在说二分之前,我觉得这道题ai的值域是<= n ,这不是就联想到权值线段树/树状数组了吗?(事实上也确实有这样的做法)
不过因为这是我听二分课的例题就果断二分了
如果二分答案的话,我们定义b[i] , 且a[i] > mid则b[i] = 1 ,否则为0,当然mid增加的话,b[i]为1的会减少,否则增大,满足二分的单调性
因此b[i]是个只有0和1的数组,我们想对其排序,不就是把该区间的1全部移到右边或左边吗?线段树可以解决区间覆盖问题(话说大家看到此题也立马觉得要用些有趣的数据结构了吧)
本题坑点(其实也不算很坑):
①由于线段树要被使用多次,所以注意清零
②(这应该是针对我自己的)我使用了双标记来解决覆盖问题,但是我在pushdown里面对于左右儿子只更新了它的一个标记,而未更新另一个标记,而在一些比较明显的地方我都注意过的,因此也WA了几遍
告诫:算法竞赛的代码要
始终如一!!!
AC Code:
#include<bits/stdc++.h>
#define rg register
#define il inline
#define maxn 500005
#define ll long long
#define lid id << 1
#define rid (id << 1) | 1
#define rep(a,b,c) for (rg int a = 1 ; a <= c ; a += b)
using namespace std;
il int read(){rg int x = 0 , w = 1;rg char ch = getchar();while (ch < '0' || ch > '9'){if (ch == '-') w = -1;ch = getchar();}while (ch >= '0' && ch <= '9'){x = (x << 3) + (x << 1) + ch - '0';ch = getchar();}return x * w;}
struct tree{
int l , r , max , sum , lazy1 , lazy2;
}t[maxn << 2];
int op[maxn] , x[maxn] , y[maxn] , a[maxn] , b[maxn];
void pushup(int id){
t[id].sum = t[lid].sum + t[rid].sum;
}
void pushdown(int id){
if (t[id].lazy1){
t[lid].lazy1 = 1 , t[lid].lazy2 = 0 , t[lid].sum = t[lid].r - t[lid].l + 1;
t[rid].lazy1 = 1 , t[rid].lazy2 = 0 , t[rid].sum = t[rid].r - t[rid].l + 1;
t[id].lazy1 = 0;
}
if (t[id].lazy2){
t[lid].lazy2 = 1 , t[lid].lazy1 = 0 , t[lid].sum = 0;
t[rid].lazy2 = 1 , t[rid].lazy1 = 0 , t[rid].sum = 0;
t[id].lazy2 = 0;
}
}
void build(int id,int l,int r){
t[id].l = l , t[id].r = r;
t[id].lazy1 = t[id].lazy2 = 0;
if (l == r) {t[id].sum = t[id].max = b[r];return;}
rg int mid = (l + r) >> 1;
build(lid , l , mid);
build(rid , mid + 1 , r);
pushup(id);
}
int query(int id,int l,int r){
if (t[id].l == l && t[id].r == r){
return t[id].sum;
}
pushdown(id);
rg int mid = (t[id].l + t[id].r) >> 1;
if (r <= mid) return query(lid , l , r);
else if (l > mid) return query(rid , l , r);
else {
return query(lid , l , mid) + query(rid , mid + 1 , r);
}
}
void update1(int id,int l,int r){
if (l > r) return;
if (t[id].l == l && t[id].r == r){
t[id].sum = t[id].r - t[id].l + 1;
t[id].lazy1 = 1 , t[id].lazy2 = 0;
return;
}
pushdown(id);
rg int mid = (t[id].l + t[id].r) >> 1;
if (r <= mid) update1(lid , l , r);
else if (l > mid) update1(rid , l , r);
else {
update1(lid , l , mid);update1(rid , mid + 1 , r);
}
pushup(id);
}
void update2(int id,int l,int r){
if (l > r) return;
if (t[id].l == l && t[id].r == r){
t[id].sum = 0;
t[id].lazy1 = 0 , t[id].lazy2 = 1;
return;
}
pushdown(id);
rg int mid = (t[id].l + t[id].r) >> 1;
if (r <= mid) update2(lid , l , r);
else if (l > mid) update2(rid , l , r);
else {
update2(lid , l , mid);update2(rid , mid + 1 , r);
}
pushup(id);
}
bool check(int mid , int n , int m , int q){
for (rg int i = 1 ; i <= n ; ++i) if (a[i] > mid) b[i] = 1; else b[i] = 0;
build(1 , 1 , n);
for (rg int i = 1 ; i <= m ; ++i){
rg int sumn = query(1 , x[i] , y[i]);
if (!op[i]){
update1(1 , y[i] - sumn + 1 , y[i]);
update2(1 , x[i] , y[i] - sumn);
}else{
update2(1 , x[i] + sumn , y[i]);
update1(1 , x[i] , x[i] + sumn - 1);
}
}
return !query(1 , q , q);
}
int main(){
rg int n = read() , m = read();
for (rg int i = 1 ; i <= n ; ++i)
a[i] = read();
for (rg int i = 1 ; i <= m ; ++i)
op[i] = read() , x[i] = read() , y[i] = read();
rg int q = read();
rg int l = 1 , r = n;
rg int ans;
while (l <= r){
rg int mid = (l + r) >> 1;
if (check(mid , n , m , q)) ans = mid , r = mid - 1;
else l = mid + 1;
}
cout << ans;
return 0;
}