 /**//*
题意:给出一个序列,Q个询问,问[x,y]内数字之和(去掉重复数字)
n <= 30000 Q <= 100000

一开始我想的是在线处理,怎么都构造不出

离线处理
对查询按照右端点排序,用last记录上一次插入的位置(这时a[1 last]都插入过),同时用pre[x]记录值为x
的最后一个位置 (pre[]可用map实现,也可以离散化实现)
这样,当遇到一个值x,之前还没插入的话就直接在该位置插入
否则,先删除上一次插入的位置,再插入
这样子,只保留每个值的最后一个位置!!!!
最后答案就是 sum(x,y)

参考 http://hi.baidu.com/forverlin1204/blog/item/e1769a89d1789298a4c272e3.html
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>

using namespace std;

const int MAXN = 30010;
const int MAXM = 100010;

struct OP
  {
int x, y ,id;
bool operator < (const OP &B)const //一开始我按照左端点排序,是错误的,但是给我tle 不知哪里写错
 {
return y < B.y;
}
};

OP op[MAXM];
long long C[MAXN] , ans[MAXM];
int a[MAXN] , n;

inline int lowbit(int x)
  {
return x&(-x);
}

long long Sum(int p)
  {
long long ans = 0;
while(p > 0)
 {
ans += C[p];
p -= lowbit(p);
}
return ans;
}

void insert(int p , int x)
  {
while(p<=n)
 {
C[p] += x;
p += lowbit(p);
}
}

long long sum[MAXN*4];

void insert(int p ,int left , int right ,int pos ,int val)
  {
if(pos < left || right < pos)return;
sum[p] += val;
if(left == right)return;
int mid = (left+right)>>1;
insert(2*p,left,mid,pos,val);
insert(2*p+1,mid+1,right,pos,val);
}

long long query(int p ,int left, int right , int l , int r)
  {
if(l<=left && right <=r)return sum[p];
long long ans = 0;
int mid = (left + right )>>1;
if(l<=mid)ans+=query(2*p,left,mid,l,r);//注意都是l,r
if(r>mid)ans+=query(2*p+1,mid+1,right,l,r);
return ans;
}

int main()
  {
#ifdef ONLINE_JUDGE
#else
freopen("in","r",stdin);
#endif

int T , Q;
for(scanf("%d",&T); T--;)
 {
scanf("%d",&n);
for(int i = 1 ; i <= n ;i++)
scanf("%d",&a[i]);

scanf("%d",&Q);
for(int i = 0 ; i < Q ; i++)
 {
scanf("%d%d",&op[i].x,&op[i].y);
op[i].id = i;
}
sort(op,op+Q);

map<int,int> pre;
for(int i = 1 ; i <= n; i++)C[i] = 0;
//for(int i = 1 ; i <= 4*n ;i++)
// sum[i] = 0;
int last = 0;
for(int i = 0; i < Q; i++)
 {
for(int j = last + 1 ; j <= op[i].y ; j++)//这样子会铺满这个区间,所以是O(nlogn)
 {
map<int,int>::iterator it = pre.find(a[j]);
if(it != pre.end())
insert(it->second , -a[j]);
//insert(1,1,n,it->second,-a[j]);
pre[a[j]] = j;
insert(j,a[j]);
//insert(1,1,n,j,a[j]);
}
last = op[i].y;
ans[op[i].id] = Sum(op[i].y) - Sum(op[i].x-1);
//ans[op[i].id] = query(1,1,n,op[i].x,op[i].y);
}
for(int i = 0 ; i < Q; i++)
printf("%I64d\n",ans[i]);
}
return 0;
}
|