树状数组离线查询操作

hdu3333
题目戳我

题意:给你长度为n的数组,有m次询问,每次询问查询区间内不重复数之和

分析:
1)由于 n<=30000,而数组元素大小<=1e9,故有必要离散化一下,或者用map
2)首先我们对询问区间按右端点升序排序,然后对数组依次进行处理,如果当前元素未在之前出现过,则将它更新进树状数组中并记录该数出现在数组的位置;若出现了,首先将其删除(之前已经记录了位置),再重新将其更新进树状数组中。
3) 对于查询,只要处理到与区间右端点相等时,即可对其进行处理,答案=sum[r]-sum[l-1],记录答案,最后输出

代码

#include
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=3e4+5;

struct Node
{
    int l,r,k;
}q[100005];
bool cmp2(Node A,Node B){if(A.r==B.r)return A.l<B.l;else return A.r<B.r;}

ll tree[maxn],c[100005];
int b[maxn],a[maxn],vis[maxn];
int n,m;

int lowbit(int x)
{
    return x&(-x);
}
void modify(int x,int add)
{
    for(int i=x;i<=n;i+=lowbit(i)){
        tree[i]+=add;
    }
}
ll getsum(int x)
{
    ll ans=0;
    for(int i=x;i>=1;i-=lowbit(i)){
        ans+=tree[i];
    }
    return ans;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            b[i]=a[i];
        }
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&q[i].l,&q[i].r);
            q[i].k=i;
        }
        sort(b+1,b+n+1);
        for(int i=1;i<=n;i++){
            a[i]=lower_bound(b+1,b+n+1,a[i])-b;
        }
        sort(q+1,q+m+1,cmp2);
        mem(vis,0);mem(tree,0);
        int tot=1;
        for(int i=1;i<=n;i++){
            if(!vis[a[i]]){
                modify(i,b[a[i]]);vis[a[i]]=i;
            }
            else{
                modify(vis[a[i]],-b[a[i]]);
                modify(i,b[a[i]]);vis[a[i]]=i;
            }
            while(tot<=m&&q[tot].r==i){
                c[q[tot].k]=getsum(q[tot].r)-getsum(q[tot].l-1);tot++;
            }
        }
        for(int i=1;i<=m;i++){
            printf("%lld\n",c[i]);
        }
    }
    return 0;
}

hdu4417
题目戳我
题意:长度为n的数组,Mario跳的最高距离为H,m次询问,询问区间内他能跳过的数目

分析:
先将路线上的点和区间的高度进行升序排序,当当前路线上点的高度小于等于区间高度时直接加入到树状数组中,否则开始进行区间统计有多少符合题意得即可。

#include
#define ll long long
#define pii pair
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=1e5+5;

struct Node
{
    int l,r,k,h;
}q[maxn];
bool cmp2(Node A,Node B){return A.h<B.h;}
bool cmp1(pii A,pii B){if(A.first==B.first)return A.second<B.second;else return A.first<B.first;}

int tree[maxn],c[maxn];
pii a[maxn];
int n,m;

int lowbit(int x)
{
    return x&(-x);
}
void modify(int x)
{
    for(int i=x;i<=n;i+=lowbit(i)){
        tree[i]++;
    }
}
int getsum(int x)
{
    int ans=0;
    for(int i=x;i>=1;i-=lowbit(i)){
        ans+=tree[i];
    }
    return ans;
}

int main()
{
    int t,Case=0;
    scanf("%d",&t);
    while(t--){
        printf("Case %d:\n",++Case);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i].first);
            a[i].second=i;
        }
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].h);
            q[i].k=i;q[i].l++;q[i].r++;
        }
        sort(a+1,a+n+1,cmp1);
        sort(q+1,q+m+1,cmp2);
        int id=1;
        mem(tree,0);
        for(int i=1;i<=m;i++){
            while(a[id].first<=q[i].h&&id<=n){
                modify(a[id].second);id++;
            }
            c[q[i].k]=getsum(q[i].r)-getsum(q[i].l-1);
        }
        for(int i=1;i<=m;i++){
            printf("%d\n",c[i]);
        }
    }
    return 0;
}

你可能感兴趣的:(树状数组)