牛客网暑期ACM多校训练营(第一场)J.Different Integers (树状数组+思维)

题目链接

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld

题目描述

Given a sequence of integers a1, a2, ..., an and q pairs of integers (l1, r1), (l2, r2), ..., (lq, rq), find count(l1, r1), count(l2, r2), ..., count(lq, rq) where count(i, j) is the number of different integers among a1, a2, ..., ai, aj, aj + 1, ..., an.

输入描述:

The input consists of several test cases and is terminated by end-of-file.
The first line of each test cases contains two integers n and q.
The second line contains n integers a1, a2, ..., an.
The i-th of the following q lines contains two integers li and ri.

输出描述:

For each test case, print q integers which denote the result.

示例1

输入

3 2
1 2 1
1 2
1 3
4 1
1 2 3 4
1 3

输出

2
1
3

备注:

* 1 ≤ n, q ≤ 105
* 1 ≤ ai ≤ n
* 1 ≤ li, ri ≤ n
* The number of test cases does not exceed 10.

题意:给出N个数(1~N),M次询问,随后M行是询问的L和R,要求输出每个询问的答案([1,L]和[R,N]中不同种类数字的个数)

题解:首先倍增一下1~N,使得a[i+N]=a[i],那么对于每个查询L和R的结果就是查询区间[R,L+N]的不同种类元素的个数.那么剩下的就是怎么求某个区间[X,Y]的不同种类元素的个数.(有三种求和方法:树状数组,线段树,主席树~前两者需要离线来做,主席树做法我还没实现).

        对于区间[X,Y]中不同种类元素的个数=区间[X,Y]中出现的而不在区间[1,X-1]中出现的元素种类个数+区间[X,Y]与[1,X-1]相同的元素种类的个数.

        这里我们使用一个sum[i]数组表示1~i中不同种类元素的个数.那么sum[Y]-sum[X-1]表示的是在区间[X,Y]中出现而没在区间[1,X-1]中出现的不同种类元素的个数.

         对于求区间[X,Y]与[1,X-1]相同的元素种类的个数,这里采用的方法是树状数组的区间求和,求和的内容就是元素种类的个数.

对于求区间[X,Y]与[1,X-1]相同的元素种类的个数,这里采用的方法是线段树的区间求和,求和的内容就是元素种类的个数.

具体的离线操作方法如下:

         首先将询问都根据左边界升序排序好,离线维护的是一个从1开始的X值,表示1~X是已处理的数据,处理的是a[i]的数据,

具体使用了2个数组:

        定义:nxt[i]:表示元素 i 的下一次出现位置

                 g[i]:表示元素 i 对线段树查询贡献的值(该数组没用用到,为了方便解释做法使用的,其具体数据包含在树状数组的数据中)

         那么对于这样一组倍增后的数据如下:

位置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
a[ ] 1 3 4 1 2 2 3 4 1 3 4 1 2 2 3 4
nxt[] 4 7 8 9 6 13 10 11 12 15 16 0 14 0 0 0
g[ ] 0 0 0 1 0 1 1 1 1       1      

(g[ ]的值是随着X的增大一边更新的,而X是根据询问的左边界来更新的,每次询问求解前都会将X更新到当前询问的左边界)

         若是询问的是[1,7],那么更新后询问的是[7,9],上面就是只将X更新到X=7的时候的g[ ]的情况,实际是更新了1~6的nxt数据.

那么结果就是sum的差值(0)加上树状数组查询区间[7,9]的和为3,从而存储询问[1,7]的答案;

代码如下:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<vector>
using namespace std;
#define ll long long
const int maxn = 2e5 + 10;
struct question {
	int l, r, id;
}q[maxn];
int a[maxn];
int sum[maxn];                     //用于记录1~i中存在多少种数
int last[maxn];                    //用于记录每种数最后出现的位置(单纯为nxt数组服务)
int nxt[maxn];                     //用于记录每个数下一个相同数的位置
int tre[maxn];                     //树状数组的结果
int ans[maxn];                     //用于保存问题的答案
int n, m;
bool cmp(question aa, question bb) {
	return aa.l < bb.l;           
}
int lowbit(int x) {                //获得x的二进制最后一个1的数值
	return x&(-x);
}
void update(int x, int y) {        //更新
	for (int i = x; i <= n; i += lowbit(i))
		tre[i] += y;
}
int query(int x) {                 //查询
	int res = 0;
	for (int i = x; i > 0; i -= lowbit(i))
		res += tre[i];
	return res;
}
int Query(int l, int r) {
	return query(r) - query(l - 1);
}
void input() {                     //输入
	int l, r;
	for (int i = 1; i <= n; i++) { //倍增
		scanf("%d", &a[i]);
		a[i + n] = a[i];
	}
	for (int i = 0; i < m; i++) {  //修改每个询问为[R,L+N]
		scanf("%d%d", &l, &r);
		q[i].l = r;
		q[i].r = l + n;
		q[i].id = i;
	}
}
void work() {                      //处理
	n <<= 1;
	sum[0] = 0;
	for (int i = 1; i <= n; i++) {
		if (last[a[i]] == 0)       //第一次出现的元素
			sum[i] = sum[i - 1] + 1;
		else {
			sum[i] = sum[i - 1];
			nxt[last[a[i]]] = i;   //更新上一次出现的nxt值
		}
		last[a[i]] = i;
	}
	sort(q, q + m, cmp);           //左边界升序排序
	int x = 1;                     //维护的X值表示1~X都为一扫描区间
	for (int i = 0; i < m; i++) {
		while (x < q[i].l) {       //更新X同时对每个元素下个元素不为空值得情况更新
			if (nxt[x])
				update(nxt[x], 1);
			x++;
		}                          //计算该询问的答案
		ans[q[i].id] = sum[q[i].r] - sum[q[i].l - 1] + Query(q[i].l, q[i].r);
	}
}
int main() {
	while (~scanf("%d%d", &n, &m)) {
		memset(last, 0, sizeof(last));
		memset(nxt, 0, sizeof(nxt));
		memset(tre, 0, sizeof(tre));
		input();
		work();
		for (int i = 0; i < m; i++)//输出   
			printf("%d\n", ans[i]);
	}
	return 0;
}

       

猜你喜欢

转载自blog.csdn.net/weixin_41156591/article/details/81139661