首页 > 其他分享 >HH的项链 题解

HH的项链 题解

时间:2024-02-16 12:22:06浏览次数:21  
标签:ma 贝壳 int 题解 HH 项链 区间

题目描述

HH有一串由各种漂亮的贝壳组成的项链。HH相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。

HH不断地收集新的贝壳,因此他的项链变得越来越长。

有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答。。。因为项链实在是太长了。

于是,他只好求助睿智的你,来解决这个问题。

输入格式

第一行:一个整数N,表示项链的长度。

第二行:N个整数,表示依次表示项链中贝壳的编号(编号为0到1000000之间的整数)。

第三行:一个整数M,表示HH询问的个数。

接下来M行:每行两个整数,L和R(1 ≤ L ≤ R ≤ N),表示询问的区间。

输出格式

M行,每行一个整数,依次表示询问对应的答案。

样例

样例输入

6
1 2 3 4 3 5
3
1 2
3 5
2 6

样例输出

2
2
4

题解

区间查询,单点修改。。。这一看就是树状数组啊;

我们开一个树状数组t表示每个位置出现数的种类(0代表没有新数,1代表有),很容易发现难点:一个区间中,同一个数出现的频率不固定;

于是,为了避免重复,我们开一个数组ma,ma[i] 代表i这个数在前面出现的位置,每次在遍历区间时判断这个数前面是否有值,如果有,那我们就“以新换旧”,在树状数组中删去原来位置的数(即-1),并且保证每次都将新位置的数的种类+1(这两步即单点修改),最后按区间顺序进行m次区间查询(树状数组前缀和)即可;

为了实现上述思路,我们在预处理时需要将每个区间按右端点升序排列,这样就可以将上一步的ma继承下来接着用;

如果不升序排列的话,那和暴力没啥区别;

剩下的细节处理请看代码;

代码

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int n, m;
int a[1000005];
int t[1000005];
int ma[1000005]; //ma[i]表示i上一次出现的位置;
int ans[1000005];
struct sss{
	int x, y, id;
}e[1000005];
bool cmp(sss a, sss b) { //升序排序;
	return a.y < b.y;
}
int lowbit(int x) {
	return x & (-x);
}
void add_dian(int x, int k) { //单点修改;
	while(x <= n) {
		t[x] += k;
		x += lowbit(x);
	}
}
int ask_sum(int l, int r) { //区间查询;
	int ans = 0;
	int i = l - 1;
	while(i > 0) {
		ans -= t[i];
		i -= lowbit(i);
	}
	i = r;
	while(i > 0) {
		ans += t[i];
		i -= lowbit(i);
	}
	return ans;
}
int main() {
	cin >> n;
	memset(ma, 0, sizeof(ma));
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	cin >> m;
	for (int i = 1; i <= m; i++) {
		cin >> e[i].x >> e[i].y;
		e[i].id = i; //为了最后按区间顺序输出;
	}
	sort(e + 1, e + 1 + m, cmp); //排序会更改原顺序,所以要id;
	int la = 1; //每次只需要更新增多区间的值,la表示的是上一次区间终点;
	for (int i = 1; i <= m; i++) {
		for (int j = la; j <= e[i].y; j++) {
			if (ma[a[j]]) {
				add_dian(ma[a[j]], -1);
			}
			add_dian(j, 1); //每一次都把新位置存进来;
			ma[a[j]] = j;
		}
		la = e[i].y + 1;
		ans[e[i].id] = ask_sum(e[i].x, e[i].y); //树状数组中只有0和1,所以求和即为解;
	}
	for (int i = 1; i <= m; i++) {
		cout << ans[i] << endl;
	}
	return 0;
}

标签:ma,贝壳,int,题解,HH,项链,区间
From: https://www.cnblogs.com/PeppaEvenPig/p/18017038

相关文章

  • 珍珠项链
    这道题目看到\(N\)这么大,就不用想组合数学了,一般都是递推+矩阵快速幂设\(f[i][j]\)表示用\(i\)种珍珠构成长度为\(j\)的项链的种数由于矩阵快速幂要求向量长度不长但是变化时间很长,所以这里我们要把\(i\)作为向量长度,\(j\)作为变化时间,所以要考虑最后一个珠子是什么(这样递推的时......
  • 盖房子 题解
    题目描述永恒の灵魂最近得到了面积为n*m的一大块土地(高兴ING_),他想在这块土地上建造一所房子,这个房子必须是正方形的。但是,这块土地并非十全十美,上面有很多不平坦的地方(也可以叫瑕疵)。这些瑕疵十分恶心,以至于根本不能在上面盖一砖一瓦。他希望找到一块最大的正方形无瑕疵土......
  • 三角蛋糕 题解
    题目描述XP在机房里放了一块正三角形的大蛋糕,但是第二天他发现蛋糕被老鼠咬坏了。XP不想让蛋糕白白的被浪费,于是他把蛋糕分割成了一个个的小正三角形(如上图所示)。黑色的小正三角形表示老鼠把那一块咬坏了。XP想要切出一块最大的没被老鼠咬坏正三角形的蛋糕,可是最大的三角形有多......
  • CF896C Willem, Chtholly and Seniorious 题解
    题目链接:CF或者洛谷比较经典的题目看到存在随机数据以及区间赋值先别急,我们发现第四个操作是很难办的,第四个操作貌似只有暴力才好做。这个时候我们可以考虑使用珂朵莉树来做,这题也是珂朵莉树的出处。使用平衡树去写珂朵莉树的话,那么随机数据下,连续段的期望为\(\log{n}\)个,所......
  • 洛谷 P9912 [COCI 2023/2024 #2] Zatopljenje 题解
    首先发现区间中的个数等于\(\texttt{高度大于x的位置的个数}-\texttt{连续两个位置都是大于x的位置的个数}\)。具体令\(H_i=\min(h_i,h_{i+1})(i\in[1,n-1])\),那么对于一次询问答案\(ans=\sum\limits_{i=l}^{r}[h_i>x]-\sum\limits_{i=l}^{r-1}[H_i>x]\),其......
  • P9089 「SvR-2」Work 题解
    P9089「SvR-2」Work可以找到一些性质:如果串\(c(字符)+A\)合法则串\(A\)合法,反之如果串\(A\)不合法则串\(c(字符)+A\)不合法如果串\(A,B\)合法(\(len(A)<len(B)\))且\(c+A\)合法,则\(c+B\)合法,而长度最小的合法串一定是一个后缀组成的那么可以得到以下算法用一......
  • 「题解」P6130 随机红包
    在\([0,1]\)上随机撒\((n-1)\)个点划分成\(n\)段,求第\(k\)大的段长的期望。从Appleblue17老师的题解中学的,大概详细写很多一笔带过但是我不认为很简单的步骤。Part1令随机变量\(X\)为第\(k\)大的段长。\(E(X)=\int_0^1P(X=x)x\textdx=\int_0^1P(X\geqx)\text......
  • 「题解」ARC139F Many Xor Optimization Problems
    考虑线性空间的标准基底(即每个主元都只有对应向量有值),答案为所有基底异或和。对于一个秩\(k\)计算它对答案的贡献。固定主元为\(a_1<a_2<\cdots<a_k\),各种情况应该是等概率,也就是对第\(i\)个基底来说,\(a_i\)位一定为\(1\),再往下的位除了在\(a\)出现过的以外的位0/1是......
  • CF1928E题解
    ModularSequence题目传送门题解发现\(a_i+y\)与\(a_i\bmody\)均不改变\(a_i\)模\(y\)的余数,所以答案序列的每个元素均可表示为\(x\bmody+ky\)的形式,先让\(s\)减去\(n\times(x\bmody)\),再除以\(y\),这样原序列可以被划分为一个从\(\lfloor\dfrac{x}{y}\rflo......
  • luogu6600题解
    题意中的字母T可以看作一个回文的\(1\)串和回文串中心带一个向下的\(1\)串。我们先来考虑朴素做法,可以枚举这个中心然后扩展来找有几个符合要求的串。朴素做法显然复杂度不对。沿着朴素的思路优化。如果只考虑\(w\gea\)和\(h\geb\)这两个要求很容易想到容斥。此......