「解题报告」P1972 HH的项链

题目链接:HH的项链

这道题做法很多,看到有用线段树,主席树和莫队做的,但我不太会用树状数组,所以讲解一下树状数组的解法。

题干告诉我们要求区间内的贝壳的种类数,那么用树状数组怎么维护呢?我们通过一个简单的例子来理解一下。对于一个序列:1 4 3 2 4 2,我们要去求这个序列里的贝壳的个数,我们就要考虑去重,将这个序列变为1 4 3 2 0 0,这样就代表了16里的贝壳的种类数。

但是我们会发现一个问题,就是这样处理的话我们要想求36,结果就会是2,但实际上的答案应该是3,那么我们就可以把某一区间内比较靠后的贝壳,作为这一区间内这种贝壳出现的唯一次数,然后记录一下上一个同种贝壳出现的位置,更新传递一下即可。具体做法就是将询问区间的操作离线,按右端点的大小进行排序,然后一一枚举贝壳的数量即可。

代码实现:

点击查看代码
#define lowbit(x) x & (-x)
using namespace std;
const int M = 1e6 + 10;
struct node {
	int l, r, id;
	friend bool operator<(node x1,node x2) {
		if (x1.r == x2.r) return x1.l < x2.l;
		return x1.r < x2.r;
	}
} plan[M];
int n, m, k=1;
int a[M], p[M], ans[M], c[M];
void add(int x, int val) {
	for (int i = x; i <= n; i += lowbit(i))
		c[i] += val;
}
int query(int x) {
	int res = 0;
	for (int i = x; i; i -= lowbit(i))
		res += c[i];
	return res;
}
int main() {
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> a[i];
	cin >> m;
	for (int i = 1; i <= m; i++)
	{
		cin >> plan[i].l >> plan[i].r;
		plan[i].id = i;
	}
	sort(plan + 1, plan + 1 + m);
	for (int i = 1; i <= plan[m].r; i++) {
		if (!p[a[i]]) {
			p[a[i]] = i;
			add(i, 1);
		} else {
			add(p[a[i]], -1);
			p[a[i]] = i;
			add(p[a[i]], 1);
		}
		while (i == plan[k].r) {
			ans[plan[k].id] = query(plan[k].r) - query(plan[k].l-1);
			k++;
		}
	}
	for (int i = 1; i <= m; i++)
		cout << ans[i] << '\n';
	return 0;
}

作者:Aewrxuk

出处:https://www.cnblogs.com/Aewrxuk/p/17644033.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   Aewrxuk  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
more_horiz
keyboard_arrow_up light_mode palette
选择主题
点击右上角即可分享
微信分享提示