题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3874
这里用到了离线算法,先将询问排序,然后用树状树组进行操作,如果一个价值没有出现过,则将其位置加上相应价值,如果出现过,则在当前位置加上该价值,而在已经出现过该价值的位置删除该价值,相当于一个移位操作,保证相同价值总出现在最后,从而保证了算法的正确性,最后用树状数组进行求和。
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
using namespace std;
inline void RD(int &ret)
{
char c;
do
{
c=getchar();
}while(c<'0'||c>'9');
ret=c-'0';
while((c=getchar())>='0'&&c<='9')
{
ret=ret*10+(c-'0');
}
}
inline void OT(int a)
{
if(a>=10)
OT(a/10);
putchar(a%10+'0');
}
struct node1
{
int data;
int id;
}s[50005];
bool cmp1(node1 x,node1 y)
{
return x.data<y.data;
}
struct node
{
int l,r;
int id;
}q[200005];
bool cmp(node x,node y)
{
return x.r<y.r;
}
int n;
int a[50005];
__int64 c[50005];
int p[1000105]; //数组开小了,RE了两版,我也想说自己好Sb,
//p存放的是a[i],1000000以内
__int64 ans[200005];
int lowbit(int x)
{
return x&(-x);
}
void add(int k,int detal)
{
while(k<=50005)
{
c[k]+=detal;
k+=lowbit(k);
}
}
__int64 sum(int k)
{
__int64 ret=0;
while(k>0)
{
ret+=c[k];
k-=lowbit(k);
}
return ret;
}
int main()
{
int T;
int i,j;
scanf("%d",&T);
while(T--)
{
memset(c,0,sizeof(c));
memset(p,0,sizeof(p));
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
/*for(i=1;i<=n;i++)
{
scanf("%d",&s[i].data);
s[i].id=i;
}
sort(s+1,s+n+1,cmp1);
a[s[1].id]=1;
for(i=2;i<=n;i++)
{
if(s[i].data==s[i-1].data)
a[s[i].id]=a[s[i-1].id];
else
a[s[i].id]=a[s[i-1].id]+1;
}*/
int qq;
scanf("%d",&qq);
for(i=0;i<qq;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
sort(q,q+qq,cmp);
j=0;
for(i=1;i<=n;i++)
{
add(i,a[i]);
if(p[a[i]]!=0)
{
add(p[a[i]],-a[i]);
}
p[a[i]]=i;
while(q[j].r==i&&j<qq)
{
if(q[j].l>1)
ans[q[j].id]=sum(q[j].r)-sum(q[j].l-1);
else
ans[q[j].id]=sum(q[j].r);
j++;
}
if(j>=qq)
break;
}
for(i=0;i<qq;i++)
printf("%I64d\n",ans[i]);
}
return 0;
}