题意:询问某一区间的值之和,相同元素只算一次
思路,树状数组求解,由于区间相同元素只算一次,采用离线算法,把区间右端点从小到大排序,按顺序处理。
首先我们找到一个点时,记录它的下标,若在后面还有与它相同的元素,我们把之前的元素去掉,插入到当前位置,每次进行这样的一次处理,就要判断一下,处理后该点有没有等于某一询问区间的右端点,有的话直接求,因为前面已经都处理过来了,所以该点前不存在重复的点
可是我还特别郁闷,我之前一直TLE,就是那个POS数组开小了,我还是不懂为什么
代码:
#include <stdio.h>//我无语了,那个Pos数组开小了一直TLE,可整死我了
#include <iostream>
#include <cstring>
#include <string.h>
#include <cmath>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
const int M=50005;
const int N=200005;
int a[M];
int pos[1000005];//开200005不行
long long ans[N],c[M];
int n,m;
struct node
{
int s,e,num;
} inv[N];
//bool cmp(node a,node b)
//{
// return a.r<b.r;
//}
bool operator <(const node &a,const node &b)
{
return a.e<b.e;
}
int lowbit(int x)
{
return x&-x;
}
void update(int x,int v)
{
for(int i=x; i<=n; i+=lowbit(i))
c[i]+=v;
}
__int64 get_sum(int x)
{
__int64 s=0;
for(int i=x; i>0; i-=lowbit(i))
s+=c[i];
return s;
}
int nextInt()//可以优化时间
{
char c;
while (c = getchar(), c < '0' || c > '9');
int r = c - '0';
while (c = getchar(), c >= '0' && c <= '9') r = r * 10 + c - '0';
return r;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
{
//scanf("%d",&a[i]);
a[i]=nextInt();
}
scanf("%d",&m);
for(int i=1; i<=m; i++)
{
// scanf("%d%d",&inv[i].s,&inv[i].e);
inv[i].s=nextInt();
inv[i].e=nextInt();
inv[i].num=i;
}
sort(inv+1,inv+m+1);
memset(c,0,sizeof(c));
memset(pos,-1,sizeof(pos));
int h=1;
__int64 t1,t2;
for(int i=1; i<=n; i++)
{
if(pos[a[i]]!=-1)
update(pos[a[i]],-a[i]);
pos[a[i]]=i;
update(i,a[i]);
while(i==inv[h].e)
{
t2=get_sum(i);
t1=get_sum(inv[h].s-1);
t1=t2-t1;
ans[inv[h].num]=t1;
h++;
}
}
for(int i=1; i<=m; i++)
printf("%I64d\n",ans[i]);
}
return 0;
}