F little w and Discretization(权值线段树+树状数组+扫描线,***)

登录—专业IT笔试面试备考平台_牛客网

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
 

题目描述

小w向大家介绍了离散化处理的具体操作过程。离散化,把无限空间中有限的个体映射到有限的空间中去,以此提高算法的时空效率。通俗的说,离散化是在不改变数据相对大小的条件下,对数据进行相应的缩小。

假设原数组为a[]数组,将其离散化后得到b[]数组,我们要求满足b数组满足以下几点:

1、离散化数组应保留原数组的大小关系,即当a[i]>a[j]时,必有b[i]>b[j],a[i]=a[j]时,必有b[i]=b[j],a[i]<a[j]时,必有b[i]<b[j]。

2、b数组由正整数构成。

3、在满足以上两点的情况下,b数组的每个元素都要求尽可能的小。

比如说对{100,200,500,200,300}进行离散化后将会变成{1,2,4,2,3}。

为了考验大家是不是真的学会了离散处理,小w准备来考考大家。

小w现在有一个长度为n的a[]数组,下标从1到n,并且满足a[i]∈[1,1000000000]。

每次小w会选择一段L到R的子数组,问,如果把这段子数组进行离散化处理后,将会有多少个元素跟原来不同?

输入描述:

对于每组案例,首先输入一个正整数n。(1<=n<=300000)
接下来一行n个正整数a[i](1<=a[i]<=1000000000)表示a数组每个元素。
接下来一个正整数m,表示小w有m个问题。(1<=m<=300000)
接下来m行,每行两个正整数L,R(1<=L<=R<=n)表示小w选中的子数组由a[L],a[L+1],a[L+2]....a[R-1],a[R]组成,并且问你将其离散化后将会有多少个元素发生改变。

输出描述:

对于每个查询,输出一行一个整数,表示查询的答案。

示例1

输入

9
4 3 1 2 5 3 3 1 4
8
1 3
2 4
2 5
1 5
3 7
4 7
4 8
5 9

输出

2
0
1
0
1
4
1
4

说明

第一个查询表示的子数组为{4,3,1},将其离散化后得到{3,2,1},有两个元素发生变化。
第二个查询表示的子数组为{3,1,2},将其离散化后得到{3,1,2},没有任何元素元素发生变化。
第三个查询表示的子数组为{3,1,2,5},将其离散化后得到{3,1,2,4},有一个元素元素发生变化。
第四个查询表示的子数组为{4,3,1,2,5},将其离散化后得到{4,3,1,2,5},没有任何元素元素发生变化。
第五个查询表示的子数组为{1,2,5,3,3},将其离散化后得到{1,2,4,3,3},有一个元素元素发生变化。
第六个查询表示的子数组为{2,5,3,3},将其离散化后得到{1,3,2,2},有四个元素元素发生变化。
第七个查询表示的子数组为{2,5,3,3,1},将其离散化后得到{2,4,3,3,1},有一个元素元素发生变化。
第八个查询表示的子数组为{5,3,3,1,4},将其离散化后得到{4,2,2,1,3},有四个元素元素发生变化。

备注:

每个查询都是独立的,并不会改变a数组的组成。

解析:

#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <utility>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <math.h>
#include <map>
#include <sstream>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <stdio.h>
#include <tuple>
using namespace std;
typedef long long LL;
#define int LL
const LL INF = 0x3f3f3f3f3f3f3f3f;
typedef unsigned long long ULL;
typedef pair<long long, long long> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const int inf = 0x3f3f3f3f;
const LL Mod = 1 << 21;
const int N = 3e5 + 10, M = 2 * N;
int n, m;
int a[N];
struct Node {
	int l, r, id;
	int ansl, ansr, mex;
}Q[N];
int tr[N << 2], C[N];	
#define ls u<<1
#define rs u<<1|1
bool cmp1(const Node& A, const Node& B) {
	return A.r < B.r;
}
bool cmp2(const Node& A, const Node& B) {
	return A.l < B.l;
}
bool cmp3(const Node& A, const Node& B) {
	return A.id < B.id;
}
void updata(int u,int l,int r,int pos,int d) {
	if (l == r) {
		tr[u] = pos;
		return;
	}
	int mid = l + r >> 1;
	if (d <= mid) {
		updata(ls, l, mid, pos, d);
	}
	else {
		updata(rs, mid + 1, r, pos, d);
	}
	tr[u] = min(tr[ls], tr[rs]);
}
int query(int u, int l, int r, int d) {
	if (l == r) {
		return l;
	}
	int mid = l + r >> 1;
	if (tr[ls] < d) {
		return query(ls, l, mid, d);
	}
	else {
		return query(rs, mid + 1, r, d);
	}
}
void add(int x, int d) {
	for (; x <= n; x += x & -x) {
		C[x] += d;
	}
}
int ask(int x) {
	int ret = 0;
	for (; x; x -= x & -x) {
		ret += C[x];
	}
	return ret;
}
signed main() {
	memset(tr, -1, sizeof tr);
	cin >> n;
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &a[i]);
	}
	cin >> m;
	for (int i = 1; i <= m; i++) {
		scanf("%lld%lld", &Q[i].l, &Q[i].r);
		Q[i].id = i;
	}
	sort(Q + 1, Q + 1 + m, cmp1);
	for (int i = 1, pos = 1; i <= n; i++) {
		if (a[i] <= n) {
			updata(1, 1, n, i, a[i]);
			add(a[i], 1);
		}
		for (; Q[pos].r == i && pos <= m; pos++) {
			Q[pos].mex = query(1, 1, n , Q[pos].l);
			Q[pos].ansr = ask(Q[pos].mex);
			//cout << "_______________________" << Q[pos].mex <<" "<<Q[pos].ansr<<" "<<Q[pos].id<< endl;
		}
	}
	sort(Q + 1, Q + 1 + m, cmp2);
	memset(C, 0, sizeof C);
	for (int i = 0, pos = 1; i <= n; i++) {
		if (i && a[i] <= n) {
			add(a[i], 1);
		}
		for (; Q[pos].l - 1 == i && pos <= m; pos++) {
			Q[pos].ansl = ask(Q[pos].mex);
			//cout << "::::::::::::::::  " << Q[pos].ansl << " " << Q[pos].id << endl;
		}
	}
	sort(Q + 1, Q + 1 + m, cmp3);
	for (int i = 1; i <= m; i++) {
		//cout << "++++++++++++++  " << Q[i].ansr << " " << Q[i].ansl <<" "<<Q[i].mex<< endl;
		printf("%lld\n", Q[i].r - Q[i].l + 1 - (Q[i].ansr - Q[i].ansl));
	}
	return 0;
}

/*
9
4 3 1 2 5 3 3 1 4
8
1 3
2 4
2 5
1 5
3 7
4 7
4 8
5 9

*/

  • 19
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值