Luogu 4137 Rmq Problem / mex
阿新 • • 發佈:2018-08-22
har roo clas namespace eve 離線 root mes void
一個主席樹題。
一開始想著直接動態開點硬搞就可以了,每次查詢只要作一個類似於前綴和的東西看看區間有沒有滿,在主席樹上二分就可以了。
但是這樣是錯的,因為一個權值會出現很多次……然後就錯了。
所以我們考慮記錄每一個權值最後出現的位置,直接開權值下標記錄每一個權值最後出現的位置,因為是區間查詢,所以可持久化一下,這樣答案就是第一次出現位置小於$l$的最小權值,查詢方法類似。
考慮到答案只可能是$a_{i} + 1, 0$,所以直接大力把$a_{i}, a_{i} + 1,0$都丟進去離散化。
註意線段樹中權值0出現的位置不是inf,因為0也算自然數。
感覺離線下來也可以不用寫可持久化。
自己一開始還是naive
Code:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 4e5 + 5; const int M = 5e6 + 5; const int inf = 1 << 30; int n, qn, tot = 0, a[N], b[N]; inline void read(int &X) { X = 0; char ch = 0View Code; int op = 1; for(; ch > ‘9‘ || ch < ‘0‘; ch = getchar()) if(ch == ‘-‘) op = -1; for(; ch >= ‘0‘ && ch <= ‘9‘; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } inline int min(int x, int y) { return x > y ? y : x; }namespace PSegT { struct Node { int lc, rc, data; } s[M]; int root[N], nodeCnt; #define mid ((l + r) >> 1) inline void up(int p) { if(p) s[p].data = min(s[s[p].lc].data, s[s[p].rc].data); } void ins(int &p, int l, int r, int x, int pre, int v) { p = ++nodeCnt; s[p].lc = s[pre].lc, s[p].rc = s[pre].rc; if(l == r) { s[p].data = v; return; } if(x <= mid) ins(s[p].lc, l, mid, x, s[pre].lc, v); else ins(s[p].rc, mid + 1, r, x, s[pre].rc, v); up(p); } int query(int p, int l, int r, int x) { if(!p || l == r) return b[l]; if(s[s[p].lc].data < x) return query(s[p].lc, l, mid, x); else return query(s[p].rc, mid + 1, r, x); } } using namespace PSegT; int main() { read(n), read(qn); b[++tot] = 0; for(int i = 1; i <= n; i++) { read(a[i]); b[++tot] = a[i], b[++tot] = a[i] + 1; } sort(b + 1, b + tot + 1); tot = unique(b + 1, b + 1 + tot) - b - 1; root[0] = nodeCnt = 0; //s[0].data = inf; for(int i = 1; i <= n; i++) { a[i] = lower_bound(b + 1, b + 1 + tot, a[i]) - b; ins(root[i], 1, tot, a[i], root[i - 1], i); } for(int x, y; qn--; ) { read(x), read(y); printf("%d\n", query(root[y], 1, tot, x)); } return 0; }
Luogu 4137 Rmq Problem / mex