贴一个划分树套主席树

来源:互联网 发布:织梦cms 漏洞 编辑:程序博客网 时间:2024/05/17 08:05

题目大意:给一个每行每列有且只有一个元素的矩阵,每次询问(l, r, a, b, k),意义为第l到r行中元素的位置排名第a到b中元素的第k大值。

一开始yy了一个分块,由于询问有50w级别,被卡到30s才出解。。。

此题要在区间ath,bth上再维护一个k大值,因此目测只有O(logn)的区间kth才可以过。。。

众所周知,静态区间kth能达到O(logn)per operation的有主席树和划分树。而区间kth满足区间加法,却不满足区间减法,因此暂且不考虑依赖区间减法的主席树。

虽然划分树也是以区间减法完成对区间kth的操作的,但是划分树有一个很好的性质:在树的每一个节点,第a到b大值是连续的。这意味着对于全局的(a, b), 在树的每一个节点中在区间(a, b)中的元素也是连续的。并且可以发现对于一个名次区间(a, b),在划分树中对应的区间是O(logn)的(类比线段树)。这为这道题提供了解法。

对于划分树的每一个节点建立一颗主席树(也可以是划分树,不过更为复杂),对于每一个询问(l, r, a, b, k),利用划分树找到对应的O(logn)颗主席树,在将这些主席树并起来查询。这样就可以在较优复杂度内解决问题,即O(logn + log2n) = O(log2n) per operation。

对于前50%的数据(k = 1, |query| <= 500000),可以考虑划分树套O(1)查询的rmq,这样可以做到O(logn) per operation。

至此此题很好地解决了。

#include <cstdio>#include <cmath>#include <cstdlib>#include <cstring>#include <ctime>#include <cctype>#include <map>#include <set>#include <string>#include <vector>#include <algorithm>using namespace std;#ifdef WIN32#define fmt64 "%I64d"#else#define fmt64 "%lld"#endif#define PI M_PI#define oo 0x13131313#define PB push_back#define PO pop_back#define iter iterator#define MP make_pair#define fst first#define snd second#define cstr(a) (a).c_str()#define FOR(i, j, k) for (i = (j); i <= (k); ++i)#define ROF(i, j, k) for (i = (j); i >= (k); --i)#define FER(i, j, k) for (i = j[k]; i; i = i->n)#define FRE(i, a) for (i = (a).begin(); i != (a).end(); ++i)typedef unsigned int uint;typedef long long int64;typedef unsigned long long uint64;typedef long double real;template<class T> inline bool minim(T &a, const T &b) {return b < a ? a = b, 1 : 0;}template<class T> inline bool maxim(T &a, const T &b) {return b > a ? a = b, 1 : 0;}template<class T> inline T sqr(const T &a) {return a * a;}template<class T> inline void read(T &x){char c = getchar(); bool f = 0;for (; '0' > c || c > '9'; c = getchar()) if (c == '-') f = 1;x = c - '0', c = getchar();for (; '0' <= c && c <= '9'; c = getchar()) (x *= 10) += c - '0';if (f) x = -x;}#define maxn 30005#define maxv 16bool data_type;int n, Q, E, ans;int a[maxn], b[maxn], c[maxn];struct segt {segt *s, *t; int l, r, v;};segt ns[maxn * maxv * maxv * 2], *nt = ns;void build_segt(segt *&p, int l, int r){p = ++nt, p->l = l, p->r = r;if (l == r) return;build_segt(p->s, l, (l + r) >> 1);build_segt(p->t, ((l + r) >> 1) + 1, r);}void update(segt *&p, segt *f, int pos){p = ++nt, *p = *f, ++p->v;if (p->l == p->r) return;pos < p->t->l ? update(p->s, f->s, pos) : update(p->t, f->t, pos);}struct part{int v[maxn], s[maxn];segt *root[maxn];int st[maxv][maxn];};part ps[maxv], *maxdepth;void build_part(part *p, int l, int r){if (maxim(maxdepth, p), l == r) return;int *a = (p + 1)->v, i;int mid = (l + r) >> 1, x = l - 1, y = mid;FOR(i, l, r) if (p->v[i] > mid)a[++y] = p->v[i], p->s[i] = p->s[i - 1];elsea[++x] = p->v[i], p->s[i] = p->s[i - 1] + 1;build_part(p + 1, l, mid);build_part(p + 1, mid + 1, r);}int LOG2[maxn], mini;void init_st(){int i, j = 2;FOR(i, 1, n) if (LOG2[i] = LOG2[i - 1], i == j) ++LOG2[i], j <<= 1;for (part *p = ps; p <= maxdepth; ++p) {int *st = p->st[0], *v = p->v;FOR(i, 1, n) st[i] = c[v[i]];FOR(i, 1, LOG2[n]) {int *q = st; st = p->st[i];FOR(j, 1, n) st[j] = min(q[j], q[j + (1 << (i - 1))]);}}}int get_min(part *p, int l, int r){if (l == r) return c[p->v[l]];int k = LOG2[r - l + 1];return min(p->st[k][l], p->st[k][r - (1 << k) + 1]);}void init_segt(){int i;for (part *p = ps; p <= maxdepth; ++p) {segt **root = p->root; int *v = p->v;build_segt(root[0], 1, n);FOR(i, 1, n) update(root[i], root[i - 1], c[v[i]]);}}struct info {segt *v; char c;} stk[maxv * 4], *top;void get_info(part *p, int l, int r, int x, int y, int a, int b){if (a == 1 && b == y - x + 1) {minim(mini, get_min(p, x, y));*(++top) = (info){p->root[x - 1], -1};*(++top) = (info){p->root[y], 1};return;}int mid = (l + r) >> 1;int u = p->s[x - 1] - p->s[l - 1];int v = p->s[y] - p->s[l - 1];if (v - u >= b)return get_info(p + 1, l, mid, l + u, l + v - 1, a, b);if (v - u < a)return get_info(p + 1, mid + 1, r, mid + 1 + x - l - u, mid + 1 + y - l - v, a - (v - u), b - (v - u));get_info(p + 1, l, mid, l + u, l + v - 1, a, v - u);get_info(p + 1, mid + 1, r, mid + 1 + x - l - u, mid + 1 + y - l - v, 1, b - (v - u));}int get_kth(int k){int res = 0;for (int l = 1, r = n; l < r; res = l) {int mid = (l + r) >> 1, rank = 0;for (info *i = top; i > stk; --i) rank += i->v->s->v * i->c;if (k > rank) {for (info *i = top; i > stk; --i) i->v = i->v->t;l = mid + 1, k -= rank;} else {for (info *i = top; i > stk; --i) i->v = i->v->s;r = mid;}}return res;}int query(int l, int r, int a, int b, int k){top = stk, mini = oo;get_info(ps, 1, n, l, r, a, b);return data_type ? get_kth(k) : mini;}void init(){int i; read(n);FOR(i, 1, n) read(a[i]);FOR(i, 1, n) read(b[i]), c[a[i]] = b[i];FOR(i, 1, n) ps->v[i] = a[i];build_part(ps, 1, n);}int main(){freopen("eureka.in", "r", stdin);freopen("eureka.out", "w", stdout);data_type = getchar() >= 'E';init();if (data_type) init_segt();else init_st();for (read(Q), read(E); Q--; ) {int l, r, a, b, k;read(l), read(r), read(a), read(b), read(k);k = (k - 1 + E * ans) % (b - a + 1) + 1;ans = query(l, r, a, b, k);printf("%d\n", ans);}return 0;}