题目地址:HDU 3333
将询问离线保存下来,然后将数组的点离散化,记录每个值上一次出现的位置。然后枚举数组的数,若当前枚举的数前面出现过,那么就删掉前面出现过的那个位置上的数,更新当前这个位置上的数,然后那些所有询问的右端点为当前位置的就可以通过查询来得到结果了。
更新与查询用线段树来优化。
代码如下:
#include <iostream>
#include <string.h>
#include <math.h>
#include <queue>
#include <algorithm>
#include <stdlib.h>
#include <map>
#include <set>
#include <stdio.h>
using namespace std;
#define LL long long
#define pi acos(-1.0)
#pragma comment(linker, "/STACK:1024000000,1024000000")
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const double eqs=1e-3;
const int MAXN=30000+10;
#define root 0, n-1, 1
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1
struct node
{
int l, r, id;
LL ans;
}qu[MAXN<<2];
int a[MAXN], c[MAXN], b[MAXN], pos[MAXN], cnt;
LL sum[MAXN<<2];
int BS(int x)
{
int low=0, high=cnt-1, mid;
while(low<=high){
mid=low+high>>1;
if(c[mid]==x) return mid;
else if(c[mid]>x) high=mid-1;
else low=mid+1;
}
}
bool cmp(node f1, node f2)
{
return f1.r<f2.r;
}
bool cmp1(node f1, node f2)
{
return f1.id<f2.id;
}
void PushUp(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void Update(int p, int x, int l, int r, int rt)
{
if(l==r){
sum[rt]=(LL)x;
return ;
}
int mid=l+r>>1;
if(p<=mid) Update(p,x,lson);
else Update(p,x,rson);
PushUp(rt);
}
LL Query(int ll, int rr, int l, int r, int rt)
{
if(ll<=l&&rr>=r){
return sum[rt];
}
int mid=l+r>>1;
LL ans=0;
if(ll<=mid) ans+=Query(ll,rr,lson);
if(rr>mid) ans+=Query(ll,rr,rson);
return ans;
}
int main()
{
int q, i, T, n, x, j;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b,b+n);
c[0]=b[0];
cnt=1;
for(i=1;i<n;i++){
if(b[i]!=b[i-1]){
c[cnt++]=b[i];
}
}
scanf("%d",&q);
for(i=0;i<q;i++){
scanf("%d%d",&qu[i].l,&qu[i].r);
qu[i].id=i;
}
sort(qu,qu+q,cmp);
memset(pos,-1,sizeof(pos));
j=0;
for(i=0;i<n;i++){
x=BS(a[i]);
if(pos[x]!=-1){
Update(pos[x],0,root);
}
Update(i,a[i],root);
pos[x]=i;
while(qu[j].r==i+1){
qu[j].ans=Query(qu[j].l-1,qu[j].r-1,root);
j++;
}
}
sort(qu,qu+q,cmp1);
for(i=0;i<q;i++){
printf("%lld\n",qu[i].ans);
}
}
return 0;
}