1. 程式人生 > >[Luogu2824] [HEOI2016/TJOI2016]排序

[Luogu2824] [HEOI2016/TJOI2016]排序

size 河北 次數 如果 lazy 姐姐 mean 復制 register

題目描述

在2016年,佳媛姐姐喜歡上了數字序列。因而他經常研究關於序列的一些奇奇怪怪的問題,現在他在研究一個難題,需要你來幫助他。這個難題是這樣子的:給出一個1到n的全排列,現在對這個全排列序列進行m次局部排序,排序分為兩種:1:(0,l,r)表示將區間[l,r]的數字升序排序2:(1,l,r)表示將區間[l,r]的數字降序排序最後詢問第q位置上的數字。

輸入輸出格式

輸入格式:

輸入數據的第一行為兩個整數n和m。n表示序列的長度,m表示局部排序的次數。1 <= n, m <= 10^5第二行為n個整數,表示1到n的一個全排列。接下來輸入m行,每一行有三個整數op, l, r, op為0代表升序排序,op為1代表降序排序, l, r 表示排序的區間。最後輸入一個整數q,q表示排序完之後詢問的位置, 1 <= q <= n。1 <= n <= 10^5,1 <= m <= 10^5

輸出格式:

輸出數據僅有一行,一個整數,表示按照順序將全部的部分排序結束後第q位置上的數字。

輸入輸出樣例

輸入樣例#1: 復制
6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3
輸出樣例#1: 復制
5

說明

河北省選2016第一天第二題。原題的時限為6s,但是洛谷上是1s,所以洛谷的數據中,對於30%的數據,有 n,m<=1000,對於100%的數據,有 n,m<=30000


二分答案的大小mid。

大於等於mid設為1,其余的設為0.

這樣可以用線段樹實現$\large O(logN)$排序。

這樣排序結束之後如果位置p是1, 就增大l, 否則減小r。


#include <iostream>
#include <cstdio>
using namespace std;
#define reg register
inline int read() {
    int res = 0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48), ch=getchar();
    return
res; } #define N 100010 int n, m, p, erf; int ans; int a[N]; struct Que { int l, r, opt; }q[N]; int cnt[N*4], lazy[N*4]; #define ls(o) o << 1 #define rs(o) o << 1 | 1 inline void pushup(int o) { cnt[o] = cnt[ls(o)] + cnt[rs(o)]; } void Build(int l, int r, int o) { lazy[o] = -1; if (l == r) { cnt[o] = (a[l] >= erf); lazy[o] = -1; return ; } int mid = l + r >> 1; Build(l, mid, ls(o)); Build(mid + 1, r, rs(o)); pushup(o); } //lazy : 1) -1 means none // 2) 1 means change to 1 // 3) 0 means change to 0 inline void pushdown(int l, int r, int o) { if (lazy[o] == -1) return ; int mid = l + r >> 1; if (lazy[o] == 1) { cnt[ls(o)] = mid - l + 1; lazy[ls(o)] = 1; cnt[rs(o)] = r - mid; lazy[rs(o)] = 1; lazy[o] = -1; } else { cnt[ls(o)] = 0, lazy[ls(o)] = 0; cnt[rs(o)] = 0, lazy[rs(o)] = 0; lazy[o] = -1; } } void change(int l, int r, int o, int ql, int qr, int c) { if (l >= ql and r <= qr) { if (c) cnt[o] = r - l + 1, lazy[o] = 1; else cnt[o] = 0, lazy[o] = 0; return; } pushdown(l, r, o); int mid = l + r >> 1; if (ql <= mid) change(l, mid, ls(o), ql, qr, c); if (qr > mid) change(mid + 1, r, rs(o), ql, qr, c); pushup(o); } int query(int l, int r, int o, int ql, int qr) { if (l >= ql and r <= qr) return cnt[o]; pushdown(l, r, o); int mid = l + r >> 1; int res = 0; if (mid >= ql) res += query(l, mid, ls(o), ql, qr); if (mid < qr) res += query(mid + 1, r, rs(o), ql, qr); return res; } inline bool check(int mid) { erf = mid; Build(1, n, 1); // printf("mid = %d\n", mid); for (reg int i = 1 ; i <= m ; i ++) { int L = q[i].l, R = q[i].r; int c = query(1, n, 1, L, R); if (q[i].opt == 0) { //升序 change(1, n, 1, R - c + 1, R, 1); change(1, n, 1, L, R - c, 0); } else { change(1, n, 1, L, L + c - 1, 1); change(1, n, 1, L + c, R, 0); } } // printf("%d\n", query(1, n, 1, p, p)); return query(1, n, 1, p, p); } int main() { n = read(), m = read(); for (reg int i = 1 ; i <= n ; i ++) a[i] = read(); for (reg int i = 1 ; i <= m ; i ++) q[i].opt = read(), q[i].l = read(), q[i].r = read(); p = read(); int l = 1, r = n; while (l <= r) { int mid = l + r >> 1; if (check(mid)) ans = mid, l = mid + 1; else r = mid - 1; } printf("%d\n", ans); return 0; }

[Luogu2824] [HEOI2016/TJOI2016]排序