此题与3743相仿,但本题数据较大,需要用到离散化。
如何去掉重复元素呢?采用离线算法
首先将询问按右端点从小到大排序,离线处理时,记录每个元素所在位置,遇到重复元素时,从它之前出现的位置减去这个元素,这样就是的每个元素总是出现在最后。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
long long int a[301000];
long long int c[310000];
long long int flag[301000];
__int64 ss[310000];
long long int mm;
int n;
struct node
{
long long int data;
long long int pos;
}s[310000];
long long int s1[310000];
bool cmp(node x,node y)
{
return x.data<y.data;
}
struct node1
{
int ll;
int rr;
int pos;
}q[1100000];
bool cmp1(node1 x,node1 y)
{
return x.rr<y.rr;
}
int lowbit(int x)
{
return x&(-x);
}
void add(int k,int detal)
{
while(k<=n)
{
c[k]+=detal;
k+=lowbit(k);
}
}
long long int sum(int k)
{
long long int t=0;
while(k>0)
{
t+=c[k];
k-=lowbit(k);
}
return t;
}
int main()
{
int T;
int i,j;
int m;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%lld",&s[i].data);
s1[i]=s[i].data;
s[i].pos=i;
}
sort(s+1,s+n+1,cmp);
a[s[1].pos]=1;
mm=1;
for(i=2;i<=n;i++)
{
if(s[i].data==s[i-1].data)
a[s[i].pos]=a[s[i-1].pos];
else
a[s[i].pos]=a[s[i-1].pos]+1;
if(a[s[i].pos]>mm)
mm=a[s[i].pos];
}
//cout<<"mm:"<<mm<<endl;
memset(flag,0,sizeof(flag));
memset(c,0,sizeof(c));
scanf("%d",&m);
for(i=0;i<m;i++)
{
scanf("%d%d",&q[i].ll,&q[i].rr);
q[i].pos=i;
}
sort(q,q+m,cmp1);
int j=0;
for(i=1;i<=n;i++)
{
//cout<<i<<":"<<s1[i]<<endl;
if(flag[a[i]]==0)
{
add(i,s1[i]);
flag[a[i]]=i;
}
else
{
//cout<<i<<" ha "<<flag[a[i]]<<endl;
add(i,s1[i]);
add(flag[a[i]],-s1[i]);
flag[a[i]]=i;
}
while(q[j].rr==i)
{
ss[q[j].pos]=sum(q[j].rr)-sum(q[j].ll-1);
j++;
}
if(j>m)
break;
}
for(i=0;i<m;i++)
{
printf("%I64d\n",ss[i]);
}
}
return 0;
}