数数(代码源每日一题)

数数(离线树状数组处理可持久化问题)

题意

给定 \(n(1<=n<=10^5)\) 长度的数组 \(a_i(0<=a_i<=10^9)\), 进行 \(m\) 次询问,格式为 \(l,r,v\),每次询问 \(l<=i<=r\) ,有多少 \(a_i<=v\)

数数 - 题目 - Daimayuan Online Judge

思路

可先用前缀和的思想,每次询问的答案为 前 \(r\) 个数中小于等于 \(v\) 的个数 - 前 \(l-1\) 个数中小于等于 \(v\) 的个数

因此可以用可持久化线段树来处理

然而本题中,对于每次询问,大于 \(v\) 的元素无需考虑

因此也可将询问的 \(v\) 从小到大排序,每次只将小于等于 \(v\) 的元素插入树状数组中,也可用 \(nlogn\) 复杂度解决

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e5 + 10;
int n, m, ans[N], tr[N], num;
vector<int> G[N];
vector<int> alls;
PII lastp[N];
struct Query
{
	int l, r, v, id;
	bool operator<(const Query &x) const
	{
		return v < x.v;
	}
}q[N];

void clean()
{
	alls.clear();
	for (int i = 0; i <= num; i++)
	{
		tr[i] = 0;
		G[i].clear();
	}
}
int find(int x)
{
	return lower_bound(alls.begin(), alls.end(), x) - alls.begin() + 1;
}

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

void add(int idx)
{
	for (int i = idx; i <= num; i += lowbit(i))
		tr[i] += 1;
}

int sum(int idx)
{
	int res = 0;
	for (int i = idx; i; i -= lowbit(i))
		res += tr[i];
	return res;
}
int main()
{
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	int T;
	cin >> T;
	while(T--)
	{
		cin >> n >> m;
		for (int i = 1; i <= n; i++)
		{
			int x;
			cin >> x;
			alls.push_back(x);
			lastp[i] = {x, i};
		}
		for (int i = 1; i <= m; i++)
		{
			int l, r, x;
			cin >> l >> r >> x;
			q[i] = {l, r, x, i};
			alls.push_back(x);
		}
		
		
		sort(alls.begin(), alls.end());
		alls.erase(unique(alls.begin(), alls.end()), alls.end());
		
		num = alls.size();
		for (int i = 1; i <= n; i++)
		{
			int x = find(lastp[i].first);
			G[x].push_back(lastp[i].second);
		}
		
		
		sort(q + 1, q + m + 1);
		int h = 0;
		for (int i = 1; i <= m; i++)
		{
			int v = q[i].v, l = q[i].l, r = q[i].r, id = q[i].id;
			v = find(v);
			for (int j = h+1; j <= v; j++)
			{
				for (auto k : G[j])
					add(k);
			}
			h = v;
			ans[id] = sum(r) - sum(l-1);
		}
		for (int i = 1; i <= m; i++)
			cout << ans[i] << " ";
		cout << endl;
		clean();
	}
	return 0;
}
posted @ 2022-06-12 17:07  hzy0227  阅读(54)  评论(0编辑  收藏  举报