您的位置:首页 > 其它

HDU 4417 Super Mario(树状数组离线处理 or 主席树)

2017-07-23 21:28 411 查看
题意:给你n个数,m次询问,每次询问求[L, R]区间内小于等于h的数的个数。(n,m <= 1e5 )

思路:

树状数组:要求比h小的,我们可以对hi和ai从小到大排序,每次都将比查询的hi小的插入树状数组或线段树,插完后询问,然后继续插入比hi+1小的,在询问........跟点击打开链接做法类似。

主席树:跟求区间第k大做法一样,只需要修改一下query函数即可,类似线段树求区间和。

树状数组代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn =1e5+5;
int tree[maxn], ans[maxn], n, m;
struct node1
{
int v, id;
bool operator < (const node1 &a) const
{
return v < a.v;
}
}a[maxn];

struct node2
{
int l, r, h, id;
bool operator < (const node2 &a) const
{
return h < a.h;
}
}op[maxn];

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

void update(int pos, int val)
{
while(pos < maxn)
{
tree[pos] += val;
pos += lowbit(pos);
}
}

int query(int pos)
{
int res = 0;
while(pos)
{
res += tree[pos];
pos -= lowbit(pos);
}
return res;
}

int main(void)
{
int t, ca = 1;
cin >> t;
while(t--)
{
memset(tree, 0, sizeof(tree));
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i].v), a[i].id = i;
for(int i = 1; i <= m; i++)
scanf("%d%d%d", &op[i].l, &op[i].r, &op[i].h), op[i].l++, op[i].r++, op[i].id = i;
sort(a+1, a+1+n);
sort(op+1, op+1+m);
for(int i = 1, j = 1; i <= m; i++) //注意中间条件不能加j<=n,因为可能j已经更新完,询问还没询问完
{
//i命令
while(j <= n && a[j].v <= op[i].h)
update(a[j].id, 1), j++;
ans[op[i].id] = query(op[i].r)-query(op[i].l-1);
}
printf("Case %d:\n", ca++);
for(int i = 1; i <= m; i++)
printf("%d\n", ans[i]);
}
return 0;
}


主席树代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1e5+5;
int a[maxn], Hash[maxn];
int lson[maxn<<5], rson[maxn<<5], sum[maxn<<5];
int T[maxn];
int m, n, tot;

int build(int l, int r)
{
int rt = ++tot;
sum[rt] = 0;
if(l < r)
{
int mid = (l+r)/2;
lson[rt] = build(l, mid);
rson[rt] = build(mid+1, r);
}
return rt;
}

int update(int pre, int l, int r, int x)
{
int rt = ++tot;
lson[rt] = lson[pre], rson[rt] = rson[pre], sum[rt] = sum[pre]+1;
if(l < r)
{
int mid = (l+r)/2;
if(x <= mid)
lson[rt] = update(lson[pre], l, mid, x);
else
rson[rt] = update(rson[pre], mid+1, r, x);
}
return rt;
}

int query(int u, int v, int l, int r, int k)
{
if(l >= r) return sum[v]-sum[u];
int mid = (l+r)/2;
int ans = 0;
if(k <= mid)
ans += query(lson[u], lson[v], l, mid, k);
else
{
ans += sum[lson[v]]-sum[lson[u]];
ans += query(rson[u], rson[v], mid+1, r, k);
}
return ans;
}

int main(void)
{
int t, ca = 1;
cin >> t;
while(t--)
{
scanf("%d%d", &n, &m);
tot = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
Hash[i] = a[i];
}
sort(Hash+1, Hash+1+n);
int d = unique(Hash+1, Hash+1+n)-Hash-1;
T[0] = build(1, d);
for(int i = 1; i <= n; i++)
{
int x = lower_bound(Hash+1, Hash+1+d, a[i])-Hash;
T[i] = update(T[i-1], 1, d, x);
}
printf("Case %d:\n", ca++);
while(m--)
{
int l, r, h;
scanf("%d%d%d", &l, &r, &h);
l++, r++;
int x = upper_bound(Hash+1, Hash+1+d, h)-Hash-1; //用lower_bound还需要判断是否与h相等,不相等还需减1,而upper_bound直接减1即可
if(x) printf("%d\n", query(T[l-1], T[r], 1, d, x));
else puts("0");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  HDU 主席树 树状数组