普通的数组,普通的给区间求和,然而这道题要不同的数字,也就是如果有重复数字不能加入到和中
不能有重复数字那么给线段树中加一个数字,如果有重复的那之前的就要删掉
那么查区间的时候怎么办呢
在新的数字v[n]有效前把前n个数字和(需要查询的)先算出来
所以先给区间们排序,每次查之前构造范围内的线段树
//
// main.cpp
// 3333
//
// Created by Mr.Xue on 17/7/26.
// Copyright © 2017年 Mr.Xue. All rights reserved.
//
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
map<long long,int> flag;
long long v[30005],sum[100005];
struct node
{
int l,r;
long long int val;
}a[120005];
struct nodee
{
int l,r,id;
}f[100005];
bool cmp(nodee a,nodee b)
{
return a.r<b.r;
}
void build(int l,int r,int i)
{
a[i].l=l;
a[i].r=r;
a[i].val=0;
if(l==r)
return;
int mid=(l+r)/2;
build(l,mid,i*2);
build(mid+1,r,i*2+1);
}
void insert(long long v,int id,int i)
{
if(a[i].l==a[i].r&&a[i].l==id)
{
a[i].val=v;
return;
}
int mid=(a[i].l+a[i].r)/2;
if(id<=mid)
insert(v,id,i*2);
else
insert(v,id,i*2+1);
a[i].val=a[i*2].val+a[i*2+1].val;
}
long long int find(int l,int r,int i)
{
if(a[i].l==l&&a[i].r==r)
return a[i].val;
int mid=(a[i].l+a[i].r)/2;
if(mid>=r)
return find(l,r,i*2);
else if(mid<l)
return find(l,r,i*2+1);
else
return find(l,mid,i*2)+find(mid+1,r,i*2+1);
}
int main()
{
int t,n,m,l,r;
//long long sum;
cin>>t;
while(t--)
{
cin>>n;
flag.clear();
build(1,n,1);
for(int i=1;i<=n;i++)
{
scanf("%lld",&v[i]);
//
}
cin>>m;
for(int i=0;i<m;i++)
{
scanf("%d %d",&f[i].l,&f[i].r);
f[i].id=i;
}
sort(f,f+m,cmp);
int ant=1;
for(int i=0;i<m;i++)
{
while(ant<=f[i].r)
{
if(flag[v[ant]])
insert(0,flag[v[ant]],1);
insert(v[ant],ant,1);
flag[v[ant]]=ant;
ant++;
//for(int i=1;i<=2*n-1;i++)
// cout<<a[i].val<<' ';
//cout<<endl;
}
sum[f[i].id]=find(f[i].l,f[i].r,1);
}
for(int i=0;i<m;i++)
printf("%lld\n",sum[i]);
}
return 0;
}