Description
Input
Output
Sample Input
7 3 1 5 2 6 3 7 4 2 5 3 4 4 1 1 7 3
Sample Output
5 63
静态区间第k大,这题时限比较长,暴力大法什么的就不说了,主要用来熟悉各种log的算法
第一发,二分答案+线段树
#include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<vector> #include<iostream> #include<algorithm> #include<bitset> #include<functional> using namespace std; typedef long long LL; const int maxn = 1e5 + 10; int n, m, l, r, k; struct tree { int f[20][maxn]; void insert(int x, int l, int r) { if (l == r) { scanf("%d", &f[x][l]); return; } int mid = l + r >> 1; insert(x + 1, l, mid); insert(x + 1, mid + 1, r); for (int i = l, j = l, k = mid + 1; i <= r; i++) { if ((f[x + 1][j]<f[x + 1][k] || k>r) && j <= mid) f[x][i] = f[x + 1][j++]; else f[x][i] = f[x + 1][k++]; } } int find(int x, int l, int r, int ll, int rr, int v) { if (ll <= l&&r <= rr) { return lower_bound(f[x] + l, f[x] + r + 1, v) - (f[x] + l); } else { int mid = l + r >> 1, ans = 0; if (ll <= mid) ans += find(x + 1, l, mid, ll, rr, v); if (rr > mid) ans += find(x + 1, mid + 1, r, ll, rr, v); return ans; } } }st; int main() { while (scanf("%d%d", &n, &m) != EOF) { st.insert(0, 1, n); while (m--) { scanf("%d%d%d", &l, &r, &k); int q = 1, h = n; while (q < h) { int mid = q + h >> 1; int u = st.find(0, 1, n, l, r, st.f[0][mid]); if (u > k - 1) h = mid - 1; if (u == k - 1) q = mid; if (u < k - 1) q = mid + 1; if (st.find(0, 1, n, l, r, st.f[0][h]) == k - 1) q = h; else h--; } printf("%d\n", st.f[0][q]); } } return 0; }第二发,可持久化线段树(静态主席树)(非离散化)(线段树动态建点)
#include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<vector> #include<iostream> #include<algorithm> #include<bitset> #include<functional> using namespace std; typedef long long LL; const int maxn = 4e6 + 10; const int mod = 2e9; int n, m, l, r, k; struct tree { int f[maxn], L[maxn], R[maxn], tot, first[maxn]; int newnode() { f[tot] = L[tot] = R[tot] = 0; return tot++; } void insert(int bef, int now, int l, int r, int v) { f[now] = f[bef] + 1; if (l == r) return; int mid = l + (r - l >> 1); L[now] = L[bef]; R[now] = R[bef]; if (v <= mid) { L[now] = newnode(); insert(L[bef], L[now], l, mid, v); } else { R[now] = newnode(); insert(R[bef], R[now], mid + 1, r, v); } } void add(int n) { tot = 0; for (int i = 0; i <= n; i++) first[i] = newnode(); for (int i = 1; i <= n; i++) { int x; scanf("%d", &x); insert(first[i - 1], first[i], 0, mod, x + mod / 2); } } int find(int bef, int now, int l, int r, int v) { if (l == r) return l - mod / 2; int mid = l + (r - l >> 1); if (v <= f[L[now]] - f[L[bef]]) return find(L[bef], L[now], l, mid, v); else return find(R[bef], R[now], mid + 1, r, v - f[L[now]] + f[L[bef]]); } }st; int main() { while (scanf("%d%d", &n, &m) != EOF) { st.add(n); while (m--) { scanf("%d%d%d", &l, &r, &k); printf("%d\n", st.find(st.first[l - 1], st.first[r], 0, mod, k)); } } return 0; }
第三发,可持久化线段树+离散化#include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<vector> #include<iostream> #include<algorithm> #include<bitset> #include<functional> using namespace std; typedef long long LL; const int maxn = 1e5 + 10; int n, m, l, r, k, a[maxn], b[maxn], c[maxn]; struct tree { int f[maxn * 20], L[maxn * 20], R[maxn * 20], tot, first[maxn]; int newnode() { f[tot] = L[tot] = R[tot] = 0; return tot++; } void insert(int bef, int now, int l, int r, int v) { f[now] = f[bef] + 1; if (l == r) return; int mid = l + (r - l >> 1); L[now] = L[bef]; R[now] = R[bef]; if (v <= mid) { L[now] = newnode(); insert(L[bef], L[now], l, mid, v); } else { R[now] = newnode(); insert(R[bef], R[now], mid + 1, r, v); } } void add() { tot = 0; for (int i = 0; i <= n; i++) first[i] = newnode(); for (int i = 1; i <= n; i++) { insert(first[i - 1], first[i], 0, n - 1, c[i - 1]); } } int find(int bef, int now, int l, int r, int v) { if (l == r) return a[l]; int mid = l + (r - l >> 1); if (v <= f[L[now]] - f[L[bef]]) return find(L[bef], L[now], l, mid, v); else return find(R[bef], R[now], mid + 1, r, v - f[L[now]] + f[L[bef]]); } }st; int main() { while (scanf("%d%d", &n, &m) != EOF) { for (int i = 0; i < n; i++) scanf("%d", &a[i]), b[i] = a[i]; sort(a, a + n); for (int i = 0; i < n; i++) c[i] = lower_bound(a, a + n, b[i]) - a; st.add(); while (m--) { scanf("%d%d%d", &l, &r, &k); printf("%d\n", st.find(st.first[l - 1], st.first[r], 0, n - 1, k)); } } return 0; }莫队分块+treap 超时。。。#include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<vector> #include<iostream> #include<algorithm> #include<bitset> #include<functional> using namespace std; typedef long long LL; const int maxn = 1e5 + 10; const int mod = 1e9 + 7; int n, m, a[maxn], ans[maxn]; struct query { int l, r, k, b, id; void read(int x){ scanf("%d%d%d", &l, &r, &k); id = x; } }c[maxn]; bool cmpl(const query&a, const query&b) { return a.b == b.b ? a.l < b.l : a.b < b.b; } bool cmpr(const query&a, const query&b) { return a.r < b.r; } struct Node { int v, p, cnt, inc; Node *l, *r; Node(int v = 0, int p = 0) :v(v), p(p){ l = r = NULL; cnt = inc = 1; } void clear(){ if (l) l->clear(); if (r)r->clear(); delete[]this; } }; struct Treap { #define node Node* #define now (*root) Node *root; void Count(node root) { root->cnt = root->inc; if (root->l) root->cnt += root->l->cnt; if (root->r) root->cnt += root->r->cnt; } void rotate_left(node *root) { node right = now->r; now->r = right->l; right->l = now; now = right; Count(now->l); Count(now); } void rotate_right(node *root) { node left = now->l; now->l = left->r; left->r = now; now = left; Count(now->r); Count(now); } void Insert(node *root, int v, int p) { if (!now) { now = new Node(v, p); return; } if (now->v == v) now->inc++; else if (v < now->v) { Insert(&(now->l), v, p); if (now->l->p < now->p) rotate_right(root); } else { Insert(&(now->r), v, p); if (now->r->p < now->p) rotate_left(root); } Count(now); } void add(int x){ Insert(&root, x, rand() % mod); } void Delete(node *root, int v) { if (!now) return; if (v < now->v) Delete(&(now->l), v); if (v > now->v) Delete(&(now->r), v); if (v == now->v) { if (now->inc > 1) now->inc--; else if (!now->l || !now->r) { node temp = now; if (now->l) now = now->l; else now = now->r; delete[] temp; return; } else { if (now->l->p < now->r->p) { rotate_right(root); Delete(&(now->r), v); } else { rotate_left(root); Delete(&(now->l), v); } } } Count(now); } void dec(int x){ Delete(&root, x); } int find(int k) { for (node temp = root; temp;) { int left = temp->l ? temp->l->cnt : 0; if (k <= left) temp = temp->l; else if (k <= left + temp->inc) return temp->v; else { temp = temp->r; k -= left + temp->inc; } } } void clear(){ if (root) root->clear(); root = NULL; } }t; int main() { while (scanf("%d%d", &n, &m) != EOF) { t.clear(); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); for (int i = 0; i < m; i++) c[i].read(i); sort(c, c + m, cmpr); for (int i = 0; i < m; i++) c[i].b = i / sqrt(m); sort(c, c + m, cmpl); for (int i = 0, l = 1, r = 0; i < m; i++) { while (l > c[i].l) t.add(a[--l]); while (r < c[i].r) t.add(a[++r]); while (l < c[i].l) t.dec(a[l++]); while (r > c[i].r) t.dec(a[r--]); ans[c[i].id] = t.find(c[i].k); } for (int i = 0; i < m; i++) printf("%d\n", ans[i]); } return 0; }第五发,二分+线段树套treap,超时。。#include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<vector> #include<iostream> #include<algorithm> #include<bitset> #include<functional> using namespace std; typedef long long LL; const int maxn = 1e5 + 10; const int mod = 1e9 + 7; int n, m, l, r, k, a[maxn]; struct Node { int v, p, cnt, inc; Node *l, *r; Node(int v = 0, int p = 0) :v(v), p(p){ l = r = NULL; cnt = inc = 1; } void clear(){ if (l) l->clear(); if (r)r->clear(); delete[]this; } }; struct Treap { #define node Node* #define now (*root) Node *root; void Count(node root) { root->cnt = root->inc; if (root->l) root->cnt += root->l->cnt; if (root->r) root->cnt += root->r->cnt; } void rotate_left(node *root) { node right = now->r; now->r = right->l; right->l = now; now = right; Count(now->l); Count(now); } void rotate_right(node *root) { node left = now->l; now->l = left->r; left->r = now; now = left; Count(now->r); Count(now); } void Insert(node *root, int v, int p) { if (!now) { now = new Node(v, p); return; } if (now->v == v) now->inc++; else if (v < now->v) { Insert(&(now->l), v, p); if (now->l->p < now->p) rotate_right(root); } else { Insert(&(now->r), v, p); if (now->r->p < now->p) rotate_left(root); } Count(now); } void add(int x){ Insert(&root, x, rand() % mod); } void Delete(node *root, int v) { if (!now) return; if (v < now->v) Delete(&(now->l), v); if (v > now->v) Delete(&(now->r), v); if (v == now->v) { if (now->inc > 1) now->inc--; else if (!now->l || !now->r) { node temp = now; if (now->l) now = now->l; else now = now->r; delete[] temp; return; } else { if (now->l->p < now->r->p) { rotate_right(root); Delete(&(now->r), v); } else { rotate_left(root); Delete(&(now->l), v); } } } Count(now); } void dec(int x){ Delete(&root, x); } int find(int x) { int ans = 0; for (node temp = root; temp;) { int left = temp->l ? temp->l->cnt : 0; if (x < temp->v) temp = temp->l; else { if (x == temp->v) return ans + left; ans += left + temp->inc; temp = temp->r; } } return ans; } void clear(){ if (root) root->clear(); root = NULL; } }; struct Tree { Treap f[maxn * 4]; void insert(int x, int l, int r) { f[x].clear(); if (l == r) { scanf("%d", &a[l]); f[x].add(a[l]); return; } int mid = l + r >> 1; insert(x << 1, l, mid); insert(x << 1 | 1, mid + 1, r); for (int i = l; i <= r; i++) f[x].add(a[i]); } int find(int x, int l, int r, int ll, int rr, int v) { if (ll <= l&&r <= rr) return f[x].find(v); int mid = l + r >> 1, ans = 0; if (ll <= mid) ans += find(x << 1, l, mid, ll, rr, v); if (rr > mid) ans += find(x << 1 | 1, mid + 1, r, ll, rr, v); return ans; } }st; int main() { while (scanf("%d%d", &n, &m) != EOF) { st.insert(1, 1, n); sort(a + 1, a + n + 1); while (m--) { scanf("%d%d%d", &l, &r, &k); int q = 1, h = n; while (q < h) { int mid = q + h >> 1; int u = st.find(1, 1, n, l, r, a[mid]); if (u > k - 1) h = mid - 1; if (u == k - 1) q = mid; if (u < k - 1) q = mid + 1; if (st.find(1, 1, n, l, r, a[h]) == k - 1) q = h; else h--; } printf("%d\n", a[q]); } } return 0; }果然指针是在这种地方的应用实在是费时,现在改用数组版的treap就过了
#include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<vector> #include<iostream> #include<algorithm> #include<bitset> #include<functional> using namespace std; typedef long long LL; const int maxn = 1e5 + 10; const int mod = 1e9 + 7; int n, m, l, r, k, a[maxn]; struct Treaps { const static int maxn = 3e6 + 3e5; int L[maxn], R[maxn], v[maxn], p[maxn], A[maxn], C[maxn], tot; void clear(){ A[0] = L[0] = R[0] = C[0] = 0; tot = 1; } int Node(int V, int P){ L[tot] = R[tot] = 0; v[tot] = V; p[tot] = P; A[tot] = C[tot] = 1; return tot++; } void Count(int x){ C[x] = A[x] + C[L[x]] + C[R[x]]; } void rotate_right(int &x) { int y = L[x]; L[x] = R[y]; R[y] = x; C[y] = C[x]; Count(x); x = y; } void rotate_left(int &x) { int y = R[x]; R[x] = L[y]; L[y] = x; C[y] = C[x]; Count(x); x = y; } void Insert(int& x, int V, int P) { if (!x) { x = Node(V, P); return; } if (v[x] == V) ++A[x]; else if (V < v[x]) { Insert(L[x], V, P); if (p[x]>p[L[x]]) rotate_right(x); } else { Insert(R[x], V, P); if (p[x] > p[R[x]]) rotate_left(x); } Count(x); } void add(int &x, int V){ Insert(x, V, rand()); }//外部直接调用,x是树根,v是值 void Delete(int &x, int V) { if (!x) return; if (V < v[x]) Delete(L[x], V); else if (V > v[x]) Delete(R[x], V); else if (A[x] > 1) --A[x]; else if (!L[x] || !R[x]) x = L[x] + R[x]; else if (p[L[x]] < p[R[x]]){ rotate_right(x); Delete(R[x], V); } else { rotate_left(x); Delete(L[x], V); } Count(x); } void dec(int &x, int V) { Delete(x, V); }//外部直接调用,x是树根,v是值 int find(int x, int V)//返回树x中小于等于V的数字个数 { int ans = 0; for (int i = x; i; i = V < v[i] ? L[i] : R[i]) { if (v[i] <= V) ans += C[L[i]] + A[i]; } return ans; } }; struct Tree { Treaps solve; int f[maxn * 4]; void insert(int x, int l, int r) { f[x] = 0; if (l == r) { scanf("%d", &a[l]); solve.add(f[x], a[l]); return; } int mid = l + r >> 1; insert(x << 1, l, mid); insert(x << 1 | 1, mid + 1, r); for (int i = l; i <= r; i++) solve.add(f[x], a[i]); } int find(int x, int l, int r, int ll, int rr, int v) { if (ll <= l&&r <= rr) return solve.find(f[x], v); int mid = l + r >> 1, ans = 0; if (ll <= mid) ans += find(x << 1, l, mid, ll, rr, v); if (rr > mid) ans += find(x << 1 | 1, mid + 1, r, ll, rr, v); return ans; } }st; int main() { while (scanf("%d%d", &n, &m) != EOF) { st.solve.clear(); st.insert(1, 1, n); sort(a + 1, a + n + 1); while (m--) { scanf("%d%d%d", &l, &r, &k); int q = 1, h = n; while (q <= h) { int mid = q + h >> 1; int u = st.find(1, 1, n, l, r, a[mid]); if (u <= k - 1) q = mid + 1; else h = mid - 1; } printf("%d\n", a[q]); } } return 0; }