BZOJ 3489: A simple rmq problem

对每一个位置 \(i\),求出其上一次出现的位置 \(pre_i\) 以及下一次出现的位置 \(next_i\)
对一个询问来说,就是查询 \(pre_i\)\([0,l-1]\)\(i\)\([l, r]\)\(next_i\)\([r + 1, n + 1]\) 这个长方体内的最大值
那么可以用KD-tree维护
空间复杂度为 \(O(n)\),时间不知,但是跑得挺快的
也可以树套树做
考虑一个位置能对哪些区间做出贡献
即左端点在区间 \([pre_i + 1, i]\),右端点在 \([i, next_i - 1]\) 的区间
把左端点看成横坐标右端点看成纵坐标
就变成了对一个区间的贡献
查询就变成了查询一个点的值
使用线段树套线段树维护
复杂度 \(O(n \log^2 n)\)

/***** KD-tree *****/
#include <bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define pli pair<ll, int>
#define lp tree[p].l
#define rp tree[p].r
#define mid ((l + r) / 2)
#define lowbit(i) ((i) & (-i))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define rep(i,a,b) for(int i=a;i<b;i++)
#define per(i,a,b) for(int i=b-1;i>=a;i--)
#define Edg int ccnt=1,head[N],to[E],ne[E];void addd(int u,int v){to[++ccnt]=v;ne[ccnt]=head[u];head[u]=ccnt;}void add(int u,int v){addd(u,v);addd(v,u);}
#define Edgc int ccnt=1,head[N],to[E],ne[E],c[E];void addd(int u,int v,int w){to[++ccnt]=v;ne[ccnt]=head[u];c[ccnt]=w;head[u]=ccnt;}void add(int u,int v,int w){addd(u,v,w);addd(v,u,w);}
#define es(u,i,v) for(int i=head[u],v=to[i];i;i=ne[i],v=to[i])
const int MOD = 1e9 + 7;
void M(int &x) {if (x >= MOD)x -= MOD; if (x < 0)x += MOD;}
int qp(int a, int b = MOD - 2) {int ans = 1; for (; b; a = 1LL * a * a % MOD, b >>= 1)if (b & 1)ans = 1LL * ans * a % MOD; return ans % MOD;}
template<class T>T gcd(T a, T b) { while (b) { a %= b; std::swap(a, b); } return a; }
template<class T>bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
template<class T>bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
char buf[1 << 21], *p1 = buf, *p2 = buf;
inline char getc() {
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
}
inline int _() {
	int x = 0, f = 1; char ch = getc();
	while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getc(); }
	while (ch >= '0' && ch <= '9') { x = x * 10ll + ch - 48; ch = getc(); }
	return x * f;
}

const int N = 1e5 + 7;
int D, n, m, root, a[N], pos[N], pre[N], suf[N], ans;
int L[3], R[3];
struct P {
	int l, r;
	int d[3], mn[3], mx[3], val, mxv;
	P() {}
	P(int a, int b, int c, int v): val(v) {
		d[0] = a, d[1] = b, d[2] = c;
		mxv = val;
		rep (i, 0, 3) mn[i] = mx[i] = d[i];
	}
	bool operator < (const P &p) const { return d[D] < p.d[D]; }
} tree[N];

inline void tag(int p, int x) {
	chkmax(tree[p].mxv, tree[x].mxv);
	rep (i, 0, 3) chkmin(tree[p].mn[i], tree[x].mn[i]), chkmax(tree[p].mx[i], tree[x].mx[i]);
}
void pushup(int p) {
	if (lp) tag(p, lp);
	if (rp) tag(p, rp);
}
int build(int l, int r, int d) {
	if (l > r) return 0;
	D = d;
	std::nth_element(tree + l, tree + mid + 1, tree + r + 1);
	int p = mid;
	lp = build(l, mid - 1, (d + 1) % 3);
	rp = build(mid + 1, r, (d + 1) % 3);
	pushup(p);
	return p;
}
bool checkALL(int p) {
	rep (i, 0, 3) if (tree[p].mn[i] < L[i] || tree[p].mx[i] > R[i]) return 0;
	return 1;
}
bool check(int p) {
	rep (i, 0, 3) if (tree[p].d[i] < L[i] || tree[p].d[i] > R[i]) return 0;
	return 1;
}
bool pbin(int p) { 
	rep (i, 0, 3) if (tree[p].mx[i] < L[i] || tree[p].mn[i] > R[i]) return 0;
	return 1;
}
void query(int p) {
	if (!p) return;
	if (tree[p].mxv <= ans) return;
	if (checkALL(p)) { chkmax(ans, tree[p].mxv); return; }
	if (check(p)) chkmax(ans, tree[p].val);
	int dl = 0, dr = 0;
	if (lp) dl = pbin(lp);
	if (rp) dr = pbin(rp);
	if (dl > dr) {
		if (dl) query(lp);
		if (dr) query(rp);
	} else {
		if (dr) query(rp);
		if (dl) query(lp);
	}
}

int main() {
#ifdef LOCAL
	freopen("ans.out", "w", stdout);
#endif
	n = _(), m = _();
	rep (i, 1, n + 1) {
		a[i] = _();
		pre[i] = pos[a[i]];
		pos[a[i]] = i;
	}
	rep (i, 1, n + 1) pos[i] = n + 1;
	per (i, 1, n + 1) {
		suf[i] = pos[a[i]];
		pos[a[i]] = i;
	}
	rep (i, 1, n + 1) tree[i] = P(i, pre[i], suf[i], a[i]);
	root = build(1, n, 0);
	rep (i, 0, m) {
		int l = _(), r = _();
		l = (l + ans) % n + 1, r = (r + ans) % n + 1;
		if (l > r) std::swap(l, r);
		ans = 0;
		L[0] = l, R[0] = r;
		L[1] = 0, R[1] = l - 1;
		L[2] = r + 1, R[2] = n + 1;
		query(root);
		printf("%d\n", ans);
	}
#ifdef LOCAL
	printf("%.10f\n", (db)clock() / CLOCKS_PER_SEC);
#endif
	return 0;
}
#include <bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define pli pair<ll, int>
#define lp p << 1
#define rp p << 1 | 1
#define mid ((l + r) / 2)
#define lowbit(i) ((i) & (-i))
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
#define rep(i,a,b) for(int i=a;i<b;i++)
#define per(i,a,b) for(int i=b-1;i>=a;i--)
#define Edg int ccnt=1,head[N],to[E],ne[E];void addd(int u,int v){to[++ccnt]=v;ne[ccnt]=head[u];head[u]=ccnt;}void add(int u,int v){addd(u,v);addd(v,u);}
#define Edgc int ccnt=1,head[N],to[E],ne[E],c[E];void addd(int u,int v,int w){to[++ccnt]=v;ne[ccnt]=head[u];c[ccnt]=w;head[u]=ccnt;}void add(int u,int v,int w){addd(u,v,w);addd(v,u,w);}
#define es(u,i,v) for(int i=head[u],v=to[i];i;i=ne[i],v=to[i])
const int MOD = 1e9 + 7;
void M(int &x) {if (x >= MOD)x -= MOD; if (x < 0)x += MOD;}
int qp(int a, int b = MOD - 2) {int ans = 1; for (; b; a = 1LL * a * a % MOD, b >>= 1)if (b & 1)ans = 1LL * ans * a % MOD; return ans % MOD;}
template<class T>T gcd(T a, T b) { while (b) { a %= b; std::swap(a, b); } return a; }
template<class T>bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
template<class T>bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
char buf[1 << 21], *p1 = buf, *p2 = buf;
inline char getc() {
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
}
inline int _() {
	int x = 0, f = 1; char ch = getc();
	while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getc(); }
	while (ch >= '0' && ch <= '9') { x = x * 10ll + ch - 48; ch = getc(); }
	return x * f;
}

const int N = 1e5 + 7;
int n, m, a[N], pos[N], pre[N], suf[N], ans;

struct Inseg {
	static const int Nn = N * 200;
	int mx[Nn], tag[Nn];
	int ch[Nn][2], tol;
	void update(int &p, int l, int r, int x, int y, int v) {
		if (!p) p = ++tol;
		chkmax(mx[p], v);
		if (x <= l && y >= r) {
			chkmax(tag[p], v);
			return;
		}
		if (x <= mid) update(ch[p][0], l, mid, x, y, v);
		if (y > mid) update(ch[p][1], mid + 1, r, x, y, v);
	}
	void query(int p, int l, int r, int x) {
		if (!p || mx[p] <= ans) return;
		chkmax(ans, tag[p]);
		if (l == r) return;
		if (x <= mid) query(ch[p][0], l, mid, x);
		else query(ch[p][1], mid + 1, r, x);
	}
} in;
struct Outseg {
	int mx[N << 2], tag[N << 2];
	void update(int p, int l, int r, int x, int y, int z, int v) {
		chkmax(mx[p], v);
		if (x <= l && y >= r) {
			in.update(tag[p], 0, n + 1, y, z, v);
			return;
		}
		if (x <= mid) update(lp, l, mid, x, y, z, v);
		if (y > mid) update(rp, mid + 1, r, x, y, z, v);
	}
	void query(int p, int l, int r, int x, int y) {
		if (mx[p] <= ans) return;
		in.query(tag[p], 0, n + 1, y);
		if (l == r) return;
		if (x <= mid) query(lp, l, mid, x, y);
		else query(rp, mid + 1, r, x, y);
	}
} out;

int main() {
#ifdef LOCAL
	freopen("ans.out", "w", stdout);
#endif
	//printf("%f\n", (db)(sizeof(in) + sizeof(out)) / 1024 / 1024);
	n = _(), m = _();
	rep (i, 1, n + 1) {
		a[i] = _();
		pre[i] = pos[a[i]];
		pos[a[i]] = i;
	}
	rep (i, 1, n + 1) pos[i] = n + 1;
	per (i, 1, n + 1) {
		suf[i] = pos[a[i]];
		pos[a[i]] = i;
	}
	rep (i, 1, n + 1) out.update(1, 1, n, pre[i] + 1, i, suf[i] - 1, a[i]);
	rep (i, 0, m) {
		int l = _(), r = _();
		l = (l + ans) % n + 1, r = (r + ans) % n + 1;
		if (l > r) std::swap(l, r);
		ans = 0;
		out.query(1, 1, n, l, r);
		printf("%d\n", ans);
	}
#ifdef LOCAL
	printf("%.10f\n", (db)clock() / CLOCKS_PER_SEC);
#endif
	return 0;
}
posted @ 2020-03-05 22:59  Mrzdtz220  阅读(129)  评论(0)    收藏  举报