题目大意:给出n个值及m个区间和查询,求区间内所有不同的值之和
解题思路:先建立一颗空线段树,在每次更新的时候在求其值,特殊处理:先将所有查询按照右区间从小到大排序,对于排序后的每次查询做更新操作,用map标记值出现的次数,若出现次数为多次,则更新减之,保证该数只加过一次,注意区间和会很大
#include <bits/stdc++.h>
using namespace std;
const int maxn = 30000+100;
const int maxm = 100000+100;
__int64 num[maxn],ans[maxm];
map<__int64,int> mp;
struct Q
{
int s,t,index;
}q[maxm];
bool cmp(Q a,Q b)
{
return a.t < b.t;
}
struct node
{
int l,r;
__int64 value;
}tree[4*maxn];
void build(int id,int l,int r) //建树时候是建的空树
{
int mid = (l+r)>>1;
tree[id].l = l;
tree[id].r = r;
tree[id].value = 0;
if(l == r) return;
build(id*2,l,mid);
build(id*2+1,mid+1,r);
}
//更新的时候将和也更新了
void update(int id,int a,__int64 b)
{
int l = tree[id].l;
int r = tree[id].r;
if(l == r)
{
tree[id].value += b;
return ;
}
int mid=(tree[id].l+tree[id].r)>>1;
if(a <= mid)
update(id*2,a,b);
else
update(id*2+1,a,b);
tree[id].value = tree[2*id].value + tree[id*2+1].value;
}
//求区间a到b的值和
__int64 query(int id,int a,int b)
{
if(tree[id].l == a&&tree[id].r == b)
{
return tree[id].value;
}
int mid = (tree[id].l+tree[id].r)>>1;
if(b <= mid)
return query(2*id,a,b);
else if(a > mid)
return query(2*id+1,a,b);
else
return query(id*2,a,mid) + query(id*2+1,mid+1,b);
}
int main()
{
int t,n,m;
scanf("%d",&t);
while(t--)
{
mp.clear();
scanf("%d",&n);
for(int i = 1;i <= n;i++)
scanf("%I64d",&num[i]);
build(1,1,n);
scanf("%d",&m);
for(int i = 1; i <= m; i++)
{
scanf("%d%d",&q[i].s,&q[i].t);
q[i].index = i;
}
sort(q+1,q+m+1,cmp);
int j = 1;
for(int i = 1; i <= m; i++)
{
for(;j <= q[i].t; j++)
{
if(mp[num[j]])
update(1,mp[num[j]],-num[j]);
mp[num[j]] = j;
update(1,mp[num[j]],num[j]);
}
ans[q[i].index] = query(1,q[i].s,q[i].t);
}
for(int i = 1; i <= m; i++)
printf("%I64d\n",ans[i]);
}
return 0;
}