[洛谷P3332][ZJOI2013]K大數查詢
阿新 • • 發佈:2018-12-11
題目大意:有$n$個位置,$m$個操作。操作有兩種:
- $1\;l\;r\;x:$在區間$[l,r]$每個位置加上一個數$x$
- $2\;l\;r\;k:$詢問$[l,r]$中第$k$大的數是多少。
題解:樹套樹,權值線段樹套位置線段樹,要標記永久化,不然會$TLE$
卡點:沒有標記永久化,$TLE$,然後處理$tag$部分寫錯
C++ Code:
#include <cstdio> #include <algorithm> #include <cctype> namespace __IO { namespace R { int x, ch, f; inline int readsign() { f = 1; while (isspace(ch = getchar())); if (ch == '-') f = -1; for (x = ch & 15; isdigit(ch = getchar()); ) x = x * 10 + (ch & 15); return x * f; } inline int read() { while (isspace(ch = getchar())); for (x = ch & 15; isdigit(ch = getchar()); ) x = x * 10 + (ch & 15); return x; } long long X; inline long long readll() { while (isspace(ch = getchar())); for (X = ch & 15; isdigit(ch = getchar()); ) X = X * 10 + (ch & 15); return X; } } } using __IO::R::read; using __IO::R::readsign; using __IO::R::readll; #define maxn 50010 int n, m; namespace SgT2 { #define N ((maxn << 3) * 50) int lc[N], rc[N], tg[N], idx; int L, R; long long V[N]; void __insert(int &rt, const int l, const int r) { if (!rt) rt = ++idx; V[rt] += std::min(R, r) - std::max(L, l) + 1; if (L <= l && R >= r) { tg[rt]++; return ; } int mid = l + r >> 1; if (L <= mid) __insert(lc[rt], l, mid); if (R > mid) __insert(rc[rt], mid + 1, r); } void insert(int &rt, int __L, int __R) { L = __L, R = __R; __insert(rt, 1, n); } long long __query(const int rt, const int l, const int r) { if (!rt || (L <= l && R >= r)) return V[rt]; int mid = l + r >> 1; long long res = static_cast<long long> (std::min(R, r) - std::max(L, l) + 1) * tg[rt]; if (L <= mid) res += __query(lc[rt], l, mid); if (R > mid) res += __query(rc[rt], mid + 1, r); return res; } long long query(int rt, int __L, int __R) { L = __L, R = __R; return __query(rt, 1, n); } #undef N } namespace SgT { #define N (maxn << 3) const int maxl = -50000, maxr = 50000; int root[N]; int L, R, num; void __insert(const int rt, const int l, const int r) { SgT2::insert(root[rt], L, R); if (l == r) return ; int mid = l + r >> 1; if (num <= mid) __insert(rt << 1, l, mid); else __insert(rt << 1 | 1, mid + 1, r); } void insert(int __L, int __R, int __num) { L = __L, R = __R, num = __num; __insert(1, maxl, maxr); } long long pos; int __query(const int rt, const int l, const int r) { if (l == r) return l; int mid = l + r >> 1; long long tmp = SgT2::query(root[rt << 1 | 1], L, R); if (pos <= tmp) return __query(rt << 1 | 1, mid + 1, r); else { pos -= tmp; return __query(rt << 1, l, mid); } } int query(int __L, int __R, long long __pos) { L = __L, R = __R, pos = __pos; return __query(1, maxl, maxr); } #undef N } using SgT::insert; using SgT::query; int main() { n = read(), m = read(); while (m --> 0) { int op = read(), l = read(), r = read(); if (op == 1) { int c = readsign(); insert(l, r, c); } else { long long c = readll(); printf("%d\n", query(l, r, c)); } } return 0; }