您的位置:首页 > 其它

HDU 4417 —— Super Mario(树状数组,离散化,离线处理)

2014-05-14 10:27 567 查看
题目:http://acm.hdu.edu.cn/showproblem.php?pid=4417

意思比较简单,就是给N个数(下标从0开始),然后q个询问,三个参数,L,R,H,询问序列中在【L,R】这个区间上小于等于H的个数。

挺综合的一道题目。因为数字最多100000个,数值最多达10^9,所以首先要对数值进行离散化。

像这种区间查询问题,用S(X,H)表示从0开始到X,小于等于H的个数,那么每个查询就可以转化成S(R,H)-S(L-1,H),这个直接写成树状数组或线段树是比较困难的。

转成离线处理会比较简单。具体来说就是把每个查询拆成两个事件,一个对应L,一个对应R,一共有2q个事件,将所有事件从左到右排序,如果对应的位置相同,那么对应左端点的应该优先在前。

然后就是遍历0~N-1,遇到事件左端点的,用k表示H在离散化之后对应的下标,减掉SUM(k),把a[i]对应的位置添加到树状数组中,遇到右端点,就加上SUM(k)。

这样,由于到了某个i的时候,后面的数值还没加进来,所以对当前值没有影响,求出来的SUM自然就是对应0到当前端点的值。

最后在一口气将所有答案输出即可。

具体还是见代码吧。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100000
#define M 200010
struct Event{
int type;//事件类型,0表示左端点,1表示右端点
int id;//事件对应的查询的编号
int x;//事件对应的端点
int v;//事件对应的H值
bool operator < (const Event& tmp)const{
if(x==tmp.x)	return type<tmp.type;
return x<tmp.x;
}
}ev[M];
inline void in(int& num){
char c=getchar();
num=0;
while(c<48 || c>57)	c=getchar();
while(c>=48 && c<=57){
num = num*10+c-48;
c = getchar();
}
}
int t, ct, n, m, q, p, l, r, x, i, j, k;
int a
, b[M], s[M], ans
;
void add(int v){
for(;v<=m;v+=(v&(-v)))	s[v]++;
}
int sum(int v){
int res=0;
for(;v;v-=(v&(-v)))	res+=s[v];
return res;
}
int main(){
in(t);
for(ct=1; ct<=t; ct++){
in(n); in(q);
m=0;
for(i=0; i<n; i++){
in(a[i]);
b[m++]=a[i];
}
for(i=0; i<q; i++){
in(l); in(r); in(x);
ev[i<<1].type=0; ev[i<<1].id=i; ev[i<<1].x=l; ev[i<<1].v=x;
j = (i<<1)|1;
ev[j].type=1; ev[j].id=i; ev[j].x=r; ev[j].v=x;
b[m++] = x;
}
p = q<<1;
sort(ev, ev+p);
sort(b, b+m);
m = unique(b, b+m)-b;
memset(s,0,sizeof(s));
j=0;
for(i=0; i<n; i++){
//先处理掉左端点
while(j<p && ev[j].type==0 && ev[j].x==i){
k = lower_bound(b, b+m, ev[j].v)-b+1;
ans[ev[j].id] = 0 - sum(k);
j++;
}
//更新当前的a[i]
k = lower_bound(b, b+m, a[i])-b+1;
add(k);
//处理右端点
while(j<p && ev[j].type==1 && ev[j].x==i){
k = lower_bound(b, b+m, ev[j].v)-b+1;
ans[ev[j].id] += sum(k);
j++;
}
}
printf("Case %d:\n", ct);
for(i=0; i<q; i++)	printf("%d\n", ans[i]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: