求区间【L,R】的不同的数的和。
解答:这题没有离散化。先记录该位置出现的数字往前最近出现的位置,然后按查询的的右端点排序,最后一次扫描各个点同时检查右端点在该位置的询问。
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <map>
#include <algorithm>
#define LL __int64
using namespace std;
const int N=50090;
LL C[N+100];
int ss[1000006];//记录位置
int n,q;
int val[N];
int pre[N];//记录前驱val【I】的位置
struct Node
{
int L,R;
int id;
}Q[209008];
bool cmp(Node a,Node b)
{
return a.R<b.R;
}
LL ans[209008];
int lowbit(int a)
{
return a&(-a);
}
LL getsum(int p)
{
LL ans=0;
for(int i=p;i>0;i-=lowbit(i))
ans+=C[i];
return ans;
}
void Modify(int p,int c)
{
for(int i=p;i<=n+2;i+=lowbit(i))
C[i]+=c;
}
int in()
{
char ch;
int a = 0;
while((ch = getchar()) == ' ' || ch == '\n');
a += ch - '0';
while((ch = getchar()) != ' ' && ch != '\n')
{
a *= 10;
a += ch - '0';
}
return a;
}
int main()
{
int cas;
cas=in();
int T=0;
while(cas--)
{
memset(ss,0,sizeof(ss));
memset(C,0,sizeof(C));
n=in();
for(int i=1;i<=n;i++)
{
val[i]=in();
if(ss[val[i]]==0)
{
ss[val[i]]=i;
pre[i]=ss[val[i]];
}
else
{
pre[i]=ss[val[i]];
ss[val[i]]=i;
}
}
q=in();
for(int i=1;i<=q;i++)
{
Q[i].L=in();
Q[i].R=in();
Q[i].id=i;
}
sort(Q+1,Q+q+1,cmp);
int cnt=1;
for(int i=1;i<=n;i++)
{
int v=val[i];
int p=pre[i];
if(p==i)
Modify(p,v);
else
{
Modify(p,-v);
Modify(i,v);
}
while(Q[cnt].R==i)
{
ans[Q[cnt].id]=getsum(Q[cnt].R)-getsum(Q[cnt].L-1);
cnt++;
}
}
for(int i=1;i<=q;i++)
printf("%I64d\n",ans[i]);
}
return 0;
}