转自:http://blog.csdn.net/acm_baihuzi/article/details/46861109
题意:求一个区间内不重复数字的和,例如1 1 1 3,区间[1,4]的和为4。
题解:先把要求的区间按右区间升序排序,再把原来的数组按顺序依次插入树状数组,假设当前插入a[i],
先判断a[i]在之前有没有出现过,没有的话直接插入add(i,a[i]),记录这个位置;有的话就当前位置
插入a[i],上一次的位置减去a[i],add(i,a[i]); add(mp[a[i]],-a[i]);。。然后查询是否有把当前位置作为右
区间的查询Q,有的话就查询该段区间的和。
代码:
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<map>
#include<vector>
#define maxn 30010
#define M 100010
#define ll long long
using namespace std;
int n,t,q;
int a[maxn],Rl[maxn],Rr[maxn];
map<int,int>mp;
struct node {
int id;
int l,r;
} Q[M];
ll tree[maxn],ans[M];
int lowbit(int x){
return x&-x;
}
bool cmp(node a,node b) {
if(a.r==b.r)return a.l<b.l;
return a.r<b.r;
}
void add(int i,int v) {
while(i<=n) {
tree[i]+=v;
i+=lowbit(i);
}
}
ll getsum(int i) {
ll s=0;
while(i>0) {
s+=tree[i];
i-=lowbit(i);
}
return s;
}
int main() {
int i,j,k;
scanf("%d",&t);
while(t--) {
cin>>n;
for(i=1;i<=n; i++)scanf("%d",&a[i]);
cin>>q;
for(i=1;i<=q;i++) {
scanf("%d%d",&Q[i].l,&Q[i].r);
Q[i].id=i;
}
sort(Q+1,Q+1+q,cmp);
memset(tree,0,sizeof tree);
memset(Rl,0,sizeof Rl);
memset(Rr,0,sizeof Rr);
int f=1;
Rl[Q[f].r]=f;
Rr[Q[f].r]=f;
for(k=2; k<=q;) {
while(Q[f].r==Q[k].r&&k<=q)k++;
Rl[Q[f].r]=f;
Rr[Q[f].r]=k-1;
f=k;
}
mp.clear();
for(i=1; i<=n; i++) {
if(!mp[a[i]]) {
add(i,a[i]);
mp[a[i]]=i;
} else {
add(i,a[i]);
add(mp[a[i]],-a[i]);
mp[a[i]]=i;
}
if(!Rl[i])continue;
int L=Rl[i],R=Rr[i];
ll ss=getsum(i);
for(j=L; j<=R; j++) {
ll sss=ss;
sss-=getsum(Q[j].l-1);
ans[Q[j].id]=sss;
}
}
for(i=1; i<=q; i++) {
printf("%I64d\n",ans[i]);
}
}
return 0;
}