HDU 3333 分块求区间不同数和

http://acm.hdu.edu.cn/showproblem.php?pid=3333

 

题意:求区间不同数的和。

 

思路:主席树和树状数组的的做法就不介绍了,blog里有介绍过。。这里介绍一下分块的做法(本来是想去莽5919。。。结果没莽过。。。只能改改代码拿3333来练练手了)

 

这里维护每个块的值(最之前出现的位置)有序,之后就是分块套路,查询整块的时候去二分有序数组,就可以知道哪些是没有计算过的了。(显然小于L才是第一次出现)。。于是乎排序每个块之外再加一个每块的前缀和就好了。不多说看代码。。分块风格学的卿学姐的。感觉比以前自己写的清爽不少,毕竟内存不要钱嘛(误),总之很清爽233333

 

代码:

 

#include<bits/stdc++.h>

using namespace std;
const int MAXN = 30010;
int n,q,block,num,a[MAXN],belong[MAXN],L[MAXN],R[MAXN];
pair<int,int> c[MAXN],d[MAXN];
long long sum[MAXN],Q[MAXN*5];
map<int,int> mp;

int in(){
    int res=0;char c;int f=1;
    while((c=getchar())<'0' || c>'9')if(c=='-')f=-1;
    while(c>='0' && c<='9')res=res*10+c-'0',c=getchar();
    return res*f;
}

int build(int n){
    block=sqrt(n);
    num=n/block;
    if(n%block!=0) num++;
    for(int i=0;i<num;i++){
        L[i]=i*block+1;
        R[i]=(i+1)*block;
    }
    R[num-1]=n;
    int cnt=0;
    for(int i=1;i<=n;i++){
        if(i<=R[cnt]) belong[i]=cnt;
        else belong[i]=++cnt;
    }
    mp.clear();
    for(int i = 1; i<= n; i++){
        c[i]=make_pair(mp[a[i]],a[i]);
        mp[a[i]] = i;
    }
    for(int i=1;i<=n;i++) d[i]=c[i];
    for(int i=0;i<num;i++) sort(c+L[i],c+R[i]+1);
    sum[0]=0;
    for(int i=1;i<=n;i++){
        if(belong[i]==belong[i-1]) sum[i]=sum[i-1]+c[i].second;
        else sum[i]=c[i].second;
    }
}

long long query1(int l,int r){
    long long ret=0;
    if(belong[l]==belong[r]){
        for(int i=l;i<=r;i++)
            if(d[i].first<l) ret+=d[i].second;
        return ret;
    }
    for(int i=l;i<=R[belong[l]];i++)
        if(d[i].first<l) ret+=d[i].second;
    for(int i=belong[l]+1;i<belong[r];i++){
        int x=(int)(lower_bound(c+L[i],c+R[i]+1,make_pair(l,-1))-c);
        if(x!=L[i]) ret+=sum[x-1];
    }
    for(int i=L[belong[r]];i<=r;i++)
        if(d[i].first<l) ret+=d[i].second;
    return ret;
}

int main(){
    Q[0]=0;
    int t,cas=1;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i = 1; i <= n; i++) a[i]=in();
        build(n);
        scanf("%d",&q);
        int l,r;
        for(int i=1;i<=q;i++){
            l=in();r=in();
            if(r<l) swap(l,r);
            Q[i]=query1(l,r);
        }
        for(int i=1;i<=q;i++) printf("%I64d\n",Q[i]);
    }
    return 0;
}



posted @ 2016-10-25 00:05  zhangxianlong  阅读(148)  评论(0编辑  收藏  举报