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到当前端点的值。
最后在一口气将所有答案输出即可。
具体还是见代码吧。
意思比较简单,就是给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; }
相关文章推荐
- HDU 4417 Super Mario (树状数组、离线处理)
- HDU 4417 Super Mario(树状数组离线处理 or 主席树)
- HDU 4417 Super Mario (树状数组 + 离线)
- hdu 4417 树状数组 离线处理
- HDU 4417 Super Mario--离线树状数组、划分树、线段树
- HDU 4417 Super Mario(离线线段树or树状数组)
- HDU 4417 Super Mario ( 离线树状数组 )
- hdu 4417 Super Mario(划分树或树状数组)
- HDU 3874 Necklace(树状数组离线处理)
- HDU 4417 Super Mario (树状数组+离线处理)(划分树+二分答案)
- HDU 4777 Rabbit Kingdom(树状数组离线处理)
- hdu 5057 Argestes and Sequence(离线处理树状数组)
- HDU 3874 Necklace (树状数组 | 线段树 的离线处理)
- hdu 3333(树状数组,离线,离散化)
- hdu 4417 离线树状数组
- [HDU 4417] Super Mario (树状数组)
- HDU 3333 Turing Tree(树状数组离线处理)
- hdu 4417 Super Mario(树状数组+离线处理)
- HDU 3874 树状数组 + 离线处理
- HDU 4602 Magic Ball Game(离线处理,树状数组,dfs)