题目:
题解:
学到了新姿势,询问区间不同数字的和
用线段树求,先按照右端点排序,然后顺着把a[i]的值添加进去,如果有重复的就把以前位置的t掉,然后把数字从新位置加上
这里可以用map:当一个超大的判断数组来用
当然还可以用树状数组写啦,这样的话写不同元素的个数就可以操作啦
记得要用long long!
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <map>
#include <algorithm>
#define LL long long
#define N 30005
using namespace std;
struct hh
{
int x,y,bh;
}qt[100005];
LL sz[N*4],a[N],ans[100005];
map<LL,int>cc;
int cmp(hh a,hh b){return a.y<b.y;}
void updata(int now){sz[now]=sz[now<<1]+sz[(now<<1)+1];}
void change(int now,int l,int r,int x,LL val)
{
if (l==r)
{
sz[now]+=val;
return;
}
int mid=(l+r)>>1;
if (x<=mid) change(now<<1,l,mid,x,val);
else change((now<<1)+1,mid+1,r,x,val);
updata(now);
}
LL qurry(int now,int l,int r,int lrange,int rrange)
{
if (l>=lrange && r<=rrange)
return sz[now];
int mid=(l+r)>>1;LL ans=0;
if(lrange<=mid) ans+=qurry(now<<1,l,mid,lrange,rrange);
if(rrange>mid) ans+=qurry((now<<1)+1,mid+1,r,lrange,rrange);
return ans;
}
int main()
{
int T,n,i,q;
scanf("%d",&T);
while (T--)
{
cc.clear();
memset(sz,0,sizeof(sz));
scanf("%d",&n);
for (i=1;i<=n;i++)
scanf("%I64d",&a[i]);
scanf("%d",&q);
for (i=1;i<=q;i++)
{
scanf("%d%d",&qt[i].x,&qt[i].y);
qt[i].bh=i;
}
int j=1;
sort(qt+1,qt+q+1,cmp);
for (i=1;i<=q;i++)
{
for (;j<=qt[i].y;j++)
{
if (cc[a[j]]) change(1,1,n,cc[a[j]],-a[j]);
cc[a[j]]=j;
change(1,1,n,j,a[j]);
}
ans[qt[i].bh]=qurry(1,1,n,qt[i].x,qt[i].y);
}
for (i=1;i<=q;i++)
printf("%I64d\n",ans[i]);
}
}