洛谷P4396 [AHOI2013]作业 主席树+莫队套数据结构


洛谷P4396 [AHOI2013]作业


标签

  • 主席树
  • 莫队套数据结构

前言


简明题意

  • 给定一个序列,需要支持两种查询操作:
    1. 查询区间[l,r]中权值位于[a,b]的数的个数
    2. 查询区间[l,r]中权值位于[a,b]的权值种数

思路

  • 第一问直接主席树吧~(如果不卡空间)
  • 第二问其实是个莫队套数据结构的经典题目了。可以莫队套分块复杂度优秀些,莫队套权值线段树卡卡常应该也能过~具体可以看看这篇博客戳这里,那一题跟这题一样的,就是数据范围大了10倍。

注意事项

  • 主席树别写炸了惹

总结


AC代码

#include<cstdio>
#include<cmath>
#include<bitset>
#include<algorithm>
using namespace std;

const int maxn = 1e5 + 10;

int pos[maxn];
struct Query
{
	int l, r, a, b, id;
	bool operator < (const Query& a)const
	{
		if (pos[l] == pos[a.l])
			return r < a.r;
		return pos[l] < pos[a.l];
	}
}; Query query[maxn];

struct Node
{
	Node* lson;
	Node* rson;
	int l, r, sum;
	Node(int l, int r, int sum = 0)
	{
		lson = rson = NULL;
		this->l = l, this->r = r;
		this->sum = sum;
	}
}; Node* tree[maxn];

Node* build(Node* o, int l, int r)
{
	o = new Node(l, r);

	if (l == r)
		return o;

	int mid = (l + r) / 2;
	o->lson = build(o->lson, l, mid);
	o->rson = build(o->rson, mid + 1, r);

	return o;
}

Node* change(Node* o, Node* laso, int k)//添加权值k
{
	o = new Node(*laso); o->sum++;

	if (o->l == o->r)
		return o;

	int mid = (o->l + o->r) / 2;
	if (k <= mid)//改左子树,连右子树
	{
		o->rson = laso->rson;
		o->lson = change(o->lson, laso->lson, k);
	}
	else
	{
		o->lson = laso->lson;
		o->rson = change(o->rson, laso->rson, k);
	}

	return o;
}

int ask(Node* L, Node* R, int l, int r)
{
	if (l == L->l && r == L->r)
		return R->sum - L->sum;

	int mid = (L->l + L->r) / 2;
	if (r <= mid)
		return ask(L->lson, R->lson, l, r);
	else if (l > mid)
		return ask(L->rson, R->rson, l, r);
	else
		return ask(L->lson, R->lson, l, mid) + ask(L->rson, R->rson, mid + 1, r);
}

int n, q, a[maxn], len;

struct FK
{
	int cnt[maxn], b[maxn];

	void change(int x, int type)
	{
		cnt[a[x]] += type;
		b[pos[a[x]]] += type;
	}

	int ask(int l, int r)
	{
		int ans = 0;

		for (int i = l; i <= min(pos[l] * len, r); i++)
			ans += cnt[i];

		if (pos[l] != pos[r])
		for (int i = pos[r] * len - len + 1; i <= r; i++)
			ans += cnt[i];

		for (int i = pos[l] + 1; i <= pos[r] - 1; i++)
			ans += b[i];

		return ans;
	}
}; FK fk;

int cnt[maxn];
void remove(int id)
{
	if (cnt[a[id]]-- == 1)
		fk.change(id, -1);
}
void add(int id)
{
	if (cnt[a[id]]++ == 0)
		fk.change(id, 1);
}

pair<int, int> ans0[maxn];
void solve()
{
	tree[0] = build(tree[0], 1, maxn - 10);
	scanf("%d%d", &n, &q);
	len = sqrt(n);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]), pos[i] = (i - 1) / len + 1;
	for (int i = 1; i <= q; i++)
		scanf("%d%d%d%d", &query[i].l, &query[i].r, &query[i].a, &query[i].b), query[i].id = i;
	sort(query + 1, query + 1 + q);

	for (int i = 1; i <= n; i++)
		tree[i] = change(tree[i], tree[i - 1], a[i]);

	int l = 1, r = 0;
	for (int i = 1; i <= q; i++)
	{
		int L = query[i].l, R = query[i].r, a = query[i].a, b = query[i].b, id = query[i].id;
		while (l < L) remove(l++);
		while (l > L) add(--l);
		while (r < R) add(++r);
		while (r > R) remove(r--);

		ans0[id].second = ask(tree[L - 1], tree[R], a, b);
		ans0[id].first = fk.ask(a, b);

	}

	for (int i = 1; i <= q; i++)
		printf("%d %d\n", ans0[i].second, ans0[i].first);
}

int main()
{
	freopen("Testin.txt", "r", stdin);
	solve();
	return 0;
}
发布了109 篇原创文章 · 获赞 33 · 访问量 3537

猜你喜欢

转载自blog.csdn.net/weixin_42431507/article/details/99693716