HDU 3333 Turing Tree 题解(线段树+离线操作)

题目链接

题目大意

给你一个长度为\(n(n\le30000)\)的数组\(a\)

给你\(m(m\le100000)\)次查询,求出区间\([l,r]\)中出现过的数字之和(出现过多次只算一次)

题目思路

这个乍一看很像线段树,其实也是线段树

但是你会发现你根本不好去维护这个线段树

你发现没这个数组没有修改操作,都是查询操作

那么对于这种题目就应该要想到离线操作

把所有查询按照\(r\)升序排序

然后保证\([1,r]\)中若出现相同的数,则这个数只在\([1,r]\)的最右边记录

那么这样显然可以保证答案的正确性,只要有一个\(last\)数组维护每个元素前的相同元素的最近值即可

由于\(a[i]\)达到\(10^9\)\(map\)即可

代码

#include<bits/stdc++.h>
#define fi first
#define se second
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef long long ll;
const int maxn=1e5+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-6;
int n,m;
int a[maxn];
ll ans[maxn];
ll tree[maxn<<2];
struct node{
    int l,r,id;
}nd[maxn];
bool cmp(node a,node b){
    return a.r<b.r;
}
ll query(int node,int l,int r,int ql,int qr){
    //这里没有被建树,显然没有值
    if(ql<=l&&r<=qr){
        return tree[node];
    }
    int mid=(l+r)/2;
    ll sum=0;
    if(mid>=ql) sum+=query(node<<1,l,mid,ql,qr);
    if(mid<qr) sum+=query(node<<1|1,mid+1,r,ql,qr);
    return sum;
}
void update(int node,int l,int r,int pos,int val){
    if(l==r){
        tree[node]=val;
        return ;
    }
    int mid=(l+r)/2;
    if(mid>=pos)    update(node<<1,l,mid,pos,val);
    else    update(node<<1|1,mid+1,r,pos,val);
    tree[node]=tree[node<<1]+tree[node<<1|1];
}
signed main(){
    int _;scanf("%d",&_);
    while(_--){
        map<int,int>last;
        memset(tree,0,sizeof(tree));
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&nd[i].l,&nd[i].r);
            nd[i].id=i;
        }
        sort(nd+1,nd+1+m,cmp);
        int pos=1;
        for(int i=1;i<=m;i++){
            while(pos<=nd[i].r){
                if(last[a[pos]]){
                    update(1,1,n,last[a[pos]],0);
                }
                update(1,1,n,pos,a[pos]);
                last[a[pos]]=pos;
                pos++;
            }
            ans[nd[i].id]=query(1,1,n,nd[i].l,nd[i].r);
        }
        for(int i=1;i<=m;i++){
            printf("%lld\n",ans[i]);
        }
    }
    return 0;
}


posted @ 2021-04-10 15:33  hunxuewangzi  阅读(54)  评论(0编辑  收藏  举报