[树状数组+离散化] NamomoCamp Daily 6

NamomoCamp Daily 6

代码源oj网址http://oj.daimayuan.top/course/10/problem/464

题解:

离散化+树状数组。

因为 A i A_i Ai最大为1e9,而 N N N最大为1e6,离散化之后最大的值也为1e6。

对于区间 [ L i , R i ] [L_i,R_i] [Li,Ri],统计不大于 H i H_i Hi的个数,我们可以将小于等于 H i H_i Hi的位置全部赋值为1,那么求区间内的个数问题可以转化成求区间和的问题。

那我们离散化后从小到大去赋值。当当前赋值的值是要求的 H i H_i Hi时,便去求区间求和。

代码:

代码源
// Good Good Study, Day Day AC.
#include <iostream>
#include <stdio.h>
#include <cstdio>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <cstring>
#include <math.h>
#include <cmath>
#include <queue>
#include <deque>
#include <stack>
#include <vector>
#include <map>
#include <algorithm> 
#include <unordered_map>
#include <unordered_set>
#define ffor(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define rrep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define ll long long
#define INF 0x7f7f7f7f7f7f7f7f
#define inf 0x7f7f7f7f
#define PII pair<int,int>
#define int long long

using namespace std;

const int N = 1e5 + 5;
int n, T, m, qi, qnum;
int a[N], t[N], num[N];
struct Ques {
	int l, r, h, ans, id;
}q[N];
vector<int> add;
vector<int> v[N];
unordered_set<int> s;

void ready()
{
	IOS;
	cin >> T;
}

int lowbite(int x) {
	return x & (-x);
}

int find_(int x)
{
	int l = 0, r = add.size() - 1;
	while (l < r)
	{
		int mid = l + r >> 1;
		if (add[mid] >= x) r = mid;
		else l = mid + 1;
	}
	return r + 1;
}

bool cmp(Ques i, Ques j) {
	return i.h < j.h;
}

bool idd(Ques i, Ques j) {
	return i.id < j.id;
}

void addinto(int i)
{
	for (auto item : v[i]) {
		int now = item;
		while (now <= n) {
			t[now]++;
			now += lowbite(now);
		}
	}
	v[i].clear();
}

int get_ans(int x) {
	int res = 0;
	while (x) {
		res += t[x];
		x -= lowbite(x);
	}
	return res;
}

void work()
{
	cin >> n >> m;
	ffor(i, 1, n) {
		cin >> a[i];
		add.push_back(a[i]);
		s.insert(a[i]);
		num[i] = a[i];
	}
	sort(add.begin(), add.end());
	add.erase(unique(add.begin(), add.end()), add.end());
	ffor(i, 1, n) {
		a[i] = find_(a[i]);
		v[a[i]].push_back(i);
	}
	ffor(i, 1, m) {
		cin >> q[i].l >> q[i].r >> q[i].h;
		q[i].id = i;
		q[i].ans = 0;
	}
	sort(q + 1, q + m + 1, cmp);
	int qi = 1;
	for (int i = 1; i <= add.size(); i++) {
		int bef=num[v[i][0]];
		while (qi <= m && bef > q[qi].h) {
			q[qi].ans = get_ans(q[qi].r) - get_ans(q[qi].l - 1);
			qi++;
		}
		addinto(i);
	}
	while (qi <= m) {
		q[qi].ans = get_ans(q[qi].r) - get_ans(q[qi].l - 1);
		qi++;
	}
	sort(q + 1, q + m + 1, idd);
	ffor(i, 1, m) cout << q[i].ans << ' ';
	cout << '\n';
	add.clear();
	s.clear();
	mst(t, 0);
}

signed main()
{
	ready();
	while (T--)
		work();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值