HDU 4417 水题 树状数组

题目大意:给n个数字,m个询问


每次询问[L,R]区间的数字,比k小的数字有多少个。 下标从0~n-1



直接离线后树状数组,听说划分树也能过


略微更新的我的破烂离散化小板子~


#include <bits/stdc++.h>
using namespace std;

#define pr(x)	cout<< #x << " = " <<x<<" "
#define prln(x)	cout<< #x << " = " <<x<<endl

const int maxn = 123456;
int n, m;

struct ls//离散
{
	int lisan[maxn];
	int t;
	void ins(int k)
	{
		++t;
		lisan[t] =k;
	}
	void clear()
	{
		t=0;
	}
	void doit()
	{
		sort(lisan + 1, lisan + 1+ t);
		t = unique(lisan + 1, lisan + 1+ t) - (lisan + 1);
	}
	int get(int k)    //查找k的下标,k一定存在
	{
		return lower_bound(lisan + 1, lisan + 1 + t, k) - (lisan);
	}
	int get2(int k)	//查找比K大的下标,k不一定存在
	{
		return upper_bound(lisan + 1, lisan + 1 + t, k) - (lisan);
	}
	int get3(int k) //查找小于等于k的下标,k不一定存在
	{
		return get2(k) - 1;
	}
	int operator [] (int k)
	{
		return lisan[k];
	}

}lisan;

int w[maxn];
int a[maxn];//[1..i]有多少个数字

#define lowbit(x)	((x)&(-x))
void ins(int x)
{
	for (int i = x; i <= n; i += lowbit(i))
		a[i]++;
}

int find(int x)//[1..x]多少个
{
	int ret=0;
	for (int i =x; i; i -= lowbit(i))
		ret += a[i];
	return ret;
}

map<int, int>g[maxn];
vector<int>mp[maxn];

void init()
{
	scanf("%d%d", &n, &m);
	lisan.clear();
	memset(a, 0, sizeof(a));
	for (int i = 1; i <= n; ++ i)	
	{
		g[i].clear();
		mp[i].clear();
	}
	for (int i = 1; i <= n; ++ i)
	{
		scanf("%d", &w[i]);
		lisan.ins(w[i]);
	}
	lisan.ins(0x7fffffff);
	lisan.ins(-2000000000);
	lisan.doit();
	n += 2;//因为多添加一个数字,所以可能有n+1个不同的数字,[1,n+1]区间
}

int ll[maxn],rr[maxn],kk[maxn];
//g[i][j]  [1..i]区间,比j小的数字的数量

void doit()
{
	for (int i = 1; i <= m; ++ i)
	{
		scanf("%d%d%d", &ll[i], &rr[i], &kk[i]);
		++ll[i];
		++rr[i];
		mp[ll[i] - 1].push_back(kk[i]);
		mp[rr[i]].push_back(kk[i]);
	}
	
	for (int i = 1;i <= n ; ++ i)
	{
		int pos = lisan.get(w[i]);
		ins(pos);
		for (int j = 0; j != mp[i].size(); ++ j)
		{
			int tmp = mp[i][j];//比tmp小的有多少个
			pos = lisan.get3(tmp);
			int sb = find(pos);
			g[i][tmp] = sb;
		}
	}
	for (int i = 1; i <= m; ++ i)
	{
		int x, y;
		if (ll[i] == 1)	x = 0;
		else x = g[ll[i] - 1][kk[i]];
		y = g[rr[i]][kk[i]];
		printf("%d\n", y - x);
	}
}

int main()
{
	int T;
	scanf("%d",&T);
	int sb=0;
	while (T--)
	{
		++sb;
		printf("Case %d:\n", sb);
		init();
		doit();
	}
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值