[BZOJ3339] Rmq Problem(线段树)

传送门

这个题的方法好像很多啊

1.莫队暴力

2.线段树 + 离线处理

先预处理出sg[i]表示前i个数的sg值,next[i]表示i的下一位置在哪里,如果后面再没有i,那么next[i] = n + 1

然后把线段树的每个叶子节点放上sg[i]。

把询问按照左端点由小到大排序,我们考虑如何从 l ~ r 转移到 l + 1 ~ r,

会发现,当把a[l]这个数去掉之后,如果后面没有a[l]那么答案就可能会更新,

那么我们可以更新 l + 1 ~ next[l] - 1这个区间,也就是用线段树操作

#include <cstdio>
#include <iostream>
#include <algorithm>
#define N 200001
#define INF ~(1 << 31)
#define root 1, 1, n
#define ls now << 1, l, mid
#define rs now << 1 | 1, mid + 1, r
#define min(x, y) ((x) < (y) ? (x) : (y))

int n, q;
int a[N], next[N], vis[N], ans[N], mx[N << 2], sg[N];

struct node
{
	int x, y, id;
}p[N];

inline int read()
{
	int x = 0, f = 1;
	char ch = getchar();
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
	for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
	return x * f;
}

inline bool cmp(node x, node y)
{
	return x.x < y.x;
}

inline void build(int now, int l, int r)
{
	if(l == r)
	{
		mx[now] = sg[l];
		return;
	}
	mx[now] = INF;
	int mid = (l + r) >> 1;
	build(ls);
	build(rs);
}

inline void push_down(int now)
{
	if(mx[now] != INF)
	{
		mx[now << 1] = min(mx[now << 1], mx[now]);
		mx[now << 1 | 1] = min(mx[now << 1 | 1], mx[now]);
		mx[now] = INF;
	}
}

inline void update(int now, int l, int r, int x, int y, int d)
{
	if(x <= l && r <= y)
	{
		mx[now] = min(mx[now], d);
		return;
	}
	push_down(now);
	int mid = (l + r) >> 1;
	if(x <= mid) update(ls, x, y, d);
	if(mid < y) update(rs, x, y, d);
}

inline int query(int now, int l, int r, int x)
{
	if(l == r) return mx[now];
	push_down(now);
	int mid = (l + r) >> 1;
	if(x <= mid) return query(ls, x);
	else return query(rs, x);
}

int main()
{
	int i, j = 0, now = 1, nxt;
	n = read();
	q = read();
	for(i = 1; i <= n; i++) a[i] = read();
	for(i = 1; i <= n; i++)
	{
		vis[a[i]] = 1;
		while(vis[j]) j++;
		sg[i] = j;
	}
	build(root);
	for(i = 0; i <= n; i++) vis[i] = n + 1;
	for(i = n; i >= 1; i--) next[i] = vis[a[i]], vis[a[i]] = i;
	for(i = 1; i <= q; i++)
	{
		p[i].id = i;
		p[i].x = read();
		p[i].y = read();
	}
	std::sort(p + 1, p + q + 1, cmp);
	for(i = 1; i <= q; i++)
	{
		while(now < p[i].x)
		{
			if(now + 1 < next[now])
				update(root, now + 1, next[now] - 1, a[now]);
			now++;
		}
		ans[p[i].id] = query(root, p[i].y);
	}
	for(i = 1; i <= q; i++) printf("%d\n", ans[i]);
	return 0;
}

3.主席树

。。不会

 

posted @ 2017-09-19 10:29  zht467  阅读(128)  评论(0编辑  收藏  举报