美文网首页
一种区间查询问题的离线处理方法

一种区间查询问题的离线处理方法

作者: 瓜炒茄 | 来源:发表于2016-08-14 00:00 被阅读0次

给定一个固定的序列,有多次查询;每次查询某个区间的元素集合信息(去除重复值项)。

由于是序列是固定的,故可以对所有查询进行离线处理,对查询按照区间右端点从小到大排序;按此顺序处理查询,在处理查询之前维护好序列中各个值在本次查询的右端点之前最后出现的位置,我们只在最后出现的这个值的位置保留这个值,之前的位置都删除;这样区间查询的时候就不会计算到重复的值项。用map映射某个值最后出现的位置,用树状数组或者线段树维护区间信息即可。

另外如果觉得map运行速度太慢,可以尝试一种离散化处理的方法(当然会不会比map快不好说,视具体情况而定):

for (int i=1;i<=n;i++) {
    scanf("%d", &a[i]);
    b[i-1] = a[i]; //b数组最终用来存放不重复的数值
}
sort(b,b+n);
int nb = unique(b,b+n)-b;
for (int i=1;i<=n;i++){
    a[i] = lower_bound(b,b+nb,a[i])-b;
    //将原来数组元素赋值成该元素在b数组中的位置,这个位置当作key来用
}
例题1

HDU-3333
求某个区间的不重复元素的和。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
#include <cstring>
using namespace std;
#define N 100005
struct que{
    int l,r,id;
}q[N];

bool cmp(que a, que b){
    return a.r<b.r;
}

long long tree[N<<2];
long long ans[N];
int a[N];

void update(int p,int l,int r,int pos,int val){
    if (l==r){
        tree[p] += val;
    }
    else{
        int m = (l+r)>>1;
        if (pos<=m) update(p<<1,l,m,pos,val);
        else update(p<<1|1,m+1,r,pos,val);
        tree[p] = tree[p<<1]+tree[p<<1|1];
    }
}

long long query(int p,int l,int r,int L,int R){
    if (L<=l&&r<=R){
        return tree[p];
    }
    else{
        int m = (l+r)>>1;
        long long ret = 0;
        if (L<=m) ret += query(p<<1,l,m,L,R);
        if (R>m) ret += query(p<<1|1,m+1,r,L,R);
        return ret;
    }
}

int main(){

    int t;
    scanf("%d", &t);
    while(t--){
        int n,m;
        scanf("%d", &n);
        for (int i=1;i<=n;i++) scanf("%d", &a[i]);
        scanf("%d", &m);
        for (int i=0;i<m;i++){
            scanf("%d%d", &q[i].l, &q[i].r);
            q[i].id = i;
        }
        sort(q,q+m,cmp);
        map<int,int> last;
        int cnt = 0;
        memset(tree,0,sizeof(tree));
        for (int i=0;i<m;i++){
            while(cnt+1<=q[i].r){
                cnt++;
                if (last[a[cnt]]) update(1,1,n,last[a[cnt]],-a[cnt]); 
                //如果之前出现过这个值,那么删除
                last[a[cnt]] = cnt; 
                //记录最后出现的位置
                update(1,1,n,cnt,a[cnt]); 
                //在当前出现的位置加上这个值
            }
            ans[q[i].id] = query(1,1,n,q[i].l,q[i].r); //直接查询区间和即可
        }
        for (int i=0;i<m;i++) printf("%I64d\n", ans[i]);
    }

    return 0;
}
例题2

Codeforces 703D
求某个区间不重复元素的异或和,跟上一题一样的处理方法,利用异或的性质即可。

#include <iostream>
#include <map>
#include <algorithm>
#include <cstdio>
using namespace std;
#define N 1000005
struct que{
    int l,r,id;
}q[N];

bool cmp(que a,que b){
    return a.r<b.r;
}

int tree[N<<2],sum[N],a[N],ans[N];

void update(int p,int l,int r,int pos,int val){
    if (l==r) {
        tree[p] = val;
    }
    else {
        int m = (l+r)>>1;
        if (pos<=m) update(p<<1,l,m,pos,val);
        else update(p<<1|1,m+1,r,pos,val);
        tree[p] = tree[p<<1]^tree[p<<1|1];
    }
}

int query(int p,int l,int r,int L,int R){
    if (L<=l&&r<=R) {
        return tree[p];
    }
    else {
        int m = (l+r)>>1;
        int ret = 0;
        if (L<=m) ret ^= query(p<<1,l,m,L,R);
        if (R>m) ret ^= query(p<<1|1,m+1,r,L,R);
        return ret;
    }
}

int main(){

    int n,m;
    cin>>n;
    for (int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
        sum[i] = sum[i-1]^a[i];
    }
    cin>>m;
    for (int i=0;i<m;i++){
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].id = i;
    }
    sort(q,q+m,cmp);

    int cnt = 0;
    map<int,int> last;
    for (int i=0;i<m;i++){
        while(cnt+1<=q[i].r){
            cnt++;
            if (last[a[cnt]]) update(1,1,n,last[a[cnt]],0);
            last[a[cnt]] = cnt;
            update(1,1,n,cnt,a[cnt]);
        }
        ans[q[i].id] = sum[q[i].r]^sum[q[i].l-1]^query(1,1,n,q[i].l,q[i].r);
    }

    for (int i=0;i<m;i++) printf("%d\n",ans[i]);

    return 0;
}

相关文章

  • 一种区间查询问题的离线处理方法

    给定一个固定的序列,有多次查询;每次查询某个区间的元素集合信息(去除重复值项)。 由于是序列是固定的,故可以对所有...

  • [算法] 区间问题

    本文对区间查询问题常用的数据结构方法进行总结 1. 前缀和 前缀和是降低区间查询问题复杂度的一种常见预处理方法,对...

  • 在线和离线算法

    在OI/ACM中,我们常常会听到对于区间修改、区间查询等问题的处理时,大佬们口中说的“离线”,“在线”等名词,一开...

  • 线段树 + 树状数组 + ST表 模板

    线段树 区间修改+区间求和 logN 树状数组 区间求和+单点修改 logN ST表 离线查询区间最值 构造Nlo...

  • 大数据采集、清洗、处理:使用MapReduce进行离线数据分析完

    1 大数据处理的常用方法 大数据处理目前比较流行的是两种方法,一种是离线处理,一种是在线处理,基本处理架构如下: ...

  • 线段树

    一、线段树建树、单点修改、区间查询 二、线段树建树、区间修改、区间查询

  • 支持区间修改和区间查询的线段树

    这种线段树支持区间修改和区间查询,区间修改的操作通过懒惰标记(lazy tag)实现。 一道支持区间修改和区间查询...

  • 树状数组

    复习一下树状数组 树状数组 一种用于处理单点修改和区间查询的数据结构。树状数组C的定义: C[x] = Sum ...

  • 线段树(区间树)--Segement Tree

    用于解决的问题: 对于给定区间 更新:更新区间中一个元素或者一个区间的值 查询一个区间[i,j]的最大值,或者区间...

  • 蓝桥杯-2014-B组-10-小朋友排队(拓展树状数组模板)

    使用到了普通的树状数组和拓展的树状数组。普通的只能单点修改和区间查询,利用两次区间查询可以做到单点查询。如果要区间...

网友评论

      本文标题:一种区间查询问题的离线处理方法

      本文链接:https://www.haomeiwen.com/subject/vmrysttx.html