P2824 HEOI2016 排序
P2824
很妙的一个题
考虑简化版:将一个01序列排序?(logn)复杂度
线段树维护,查询区间内\(1\)的个数记为\(cnt1\),升序,将\([r-cnt1+1,r]\)改为\(1\),将\([l,r-cnt1]\)改为\(0\),降序将\([l,l+cnt1-1]\)改为\(1\),将\([l+cnt,r]\)改为\(0\),成功将排序转化为区间查询和区间修改
离线
此题二分答案\(mid\),把原序列中大等于\(mid\)标记为\(1\),小于\(mid\)标记为\(0\),对于每个操作将\(01\)序列排序,如果第\(p\)个位子仍是\(1\)的话就是可行的
如果二分一个值成立当且仅当这个位子的值大于等于\(mid\),故如果\(check\)返回\(true\),则\(l = mid+1\),否则\(r = mid-1\),
#include<cstdio>
#include<cstring>
#include<cctype>
#define lc o<<1
#define rc o<<1|1
#define mid (l+r)/2
using namespace std;
const int N = 100010;
int n, m, p;
int T[4*N], lazy[4*N];//segment tree
int a[N], ch[N], L[N], R[N];//the information by reading
inline int read()
{
char ch = getchar(); int x = 0;
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)){ x = x*10+ch-'0'; ch = getchar(); }
return x;
}
inline void build(int o, int l, int r, int x)
{
if (l == r){
T[o] = a[l] >= x;
lazy[o] = 0;
return;
}
build(lc, l, mid, x); build(rc, mid+1, r, x);
T[o] = T[lc]+T[rc]; lazy[o] = 0;
}
inline void pushdown(int o, int l, int r)
{
if (!lazy[o]) return;
lazy[lc] = lazy[rc] = lazy[o];
if (lazy[o] == 1){
T[lc] = mid-l+1; T[rc] = r-mid;
} else T[lc] = T[rc] = 0;
lazy[o] = 0;
}
inline int query(int o, int l, int r, int x, int y)
{
if (x <= l && y >= r) return T[o];
if (x > r || y < l) return 0;
pushdown(o, l, r);
return query(lc, l, mid, x, y) + query(rc, mid+1, r, x, y);
}
inline int queryPoint(int o, int l, int r, int x)
{
if (l == x && r == x) return T[o];
pushdown(o, l, r);
if (x <= mid) return queryPoint(lc, l, mid, x);
else return queryPoint(rc, mid+1, r, x);
}
inline void update(int o, int l, int r, int x, int y, int val)
{
if (x <= l && y >= r){
T[o] = val*(r-l+1); lazy[o] = val ? 1 : -1;
return;
}
if (x > r || y < l) return;
pushdown(o, l, r);
update(lc, l, mid, x, y, val);
update(rc, mid+1, r, x, y, val);
T[o] = T[lc]+T[rc];
}
inline bool check(int x)
{
build(1, 1, n, x);
for (int i = 1; i <= m; i ++){
int cnt1 = query(1, 1, n, L[i], R[i]);
if (ch[i] == 0){
update(1, 1, n, R[i]-cnt1+1, R[i], 1);
update(1, 1, n, L[i], R[i]-cnt1, 0);
}
else{
update(1, 1, n, L[i], L[i]+cnt1-1, 1);
update(1, 1, n, L[i]+cnt1, R[i], 0);
}
}
return queryPoint(1, 1, n, p);
}
int main()
{
n = read(); m = read();
for (int i = 1; i <= n; i ++) a[i] = read();
for (int i = 1; i <= m; i ++){
ch[i] = read(); L[i] = read(); R[i] = read();
}
p = read();
int ll = 1, rr = n, midd, ans;
while (ll <= rr){
midd = (ll+rr) >> 1;
if (check(midd)) ans = midd, ll = midd+1; else rr = midd-1;
}
printf("%d\n", ans);
return 0;
}