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

今天和涂涂新学的离线算法,太牛了

大概就是先接收所有数据,然后按查询右边界排序,从左往右更新,遇到之前加过的数就删掉,因为按右边界排序,所以查询区间不断右移,删掉不会出错

View Code
#include <iostream>
#include <algorithm>
#include <map>
using namespace std ;
const int maxn=50001 ;
typedef __int64 LL ;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
map <int,int> hash ;
struct node{
    int l,r,id ;
}kk[maxn<<2] ;
int a[maxn] ;
LL sum[maxn<<2] ;
LL ans[maxn<<2] ;
void pushup(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1] ;
}
void update(int p,int add,int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]+=add ;
        return ;
    }
    int m=(l+r)>>1 ;
    if(p<=m)
        update(p,add,lson) ;
    else
        update(p,add,rson) ;
    pushup(rt) ;
}
LL query(int L,int R,int l,int r,int rt)
{
    if(L<=l && R>=r)
        return sum[rt] ;
    int m=(l+r)>>1 ;
    LL ret=0 ;
    if(L<=m)
        ret+=query(L,R,lson) ;
    if(R>m)
        ret+=query(L,R,rson) ;
    return ret ;
}
bool cmp(node a,node b)
{
    return a.r<b.r ;
}
int main()
{
    int t ;
    scanf("%d",&t) ;
    while(t--)
    {
        int n ;
        scanf("%d",&n) ;
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]) ;
        int m ;
        scanf("%d",&m) ;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&kk[i].l,&kk[i].r) ;
            kk[i].id=i ;
        }
        sort(kk+1,kk+m+1,cmp) ;
        hash.clear() ;
        memset(sum,0,sizeof(sum)) ;
        int r=1 ;
        for(int i=1;i<=m;i++)
        {
            while(r<=kk[i].r)
            {
                if(hash[a[r]])
                    update(hash[a[r]],-a[r],1,n,1) ;
                update(r,a[r],1,n,1) ;
                hash[a[r]]=r ;
                r++ ;    
            }
            ans[kk[i].id]=query(kk[i].l,kk[i].r,1,n,1) ;
        }
        for(int i=1;i<=m;i++)
            printf("%I64d\n",ans[i]) ;
    }
    return 0 ;
}