HDU 3333
求一个区间内不同数的和。
这相当于求一个区间的不同数的个数。使用树状数组,离线算法,离散化,把所有要询问的区间读入,然后按区间的右端点排序。对数组从左往右扫描,设当前数字为V,记录下V上一次出现在数组的位置last[V],然后把上一次的位置last[v]在树状数组减去V,在当前位置加上V。当扫描到区间右端点时,对区间进行求和,就得到结果。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <map> #define LL __int64 #define lowbit(x) ((x)&(-(x))) using namespace std; const int N=30100; const int Q=100100; struct Query{ int l,r,Id; bool operator <(const Query &a)const{ if(r<a.r) return true; return false; } }; Query query[Q]; LL num[N],su[N],ans[Q]; int last[N],n; LL sum(int x){ if(x==0) return 0; LL s=0; for(;x;x-=lowbit(x)){ s+=su[x]; } return s; } void update(int x,LL w){ for(;x<=n;x+=lowbit(x)) su[x]+=w; } int main(){ int T; scanf("%d",&T); while(T--){ int cnt=0; scanf("%d",&n); map<LL,int>mp; su[0]=0; for(int i=1;i<=n;i++){ su[i]=last[i]=0; scanf("%I64d",&num[i]); if(!mp[num[i]]){ mp[num[i]]=++cnt; } } int q; scanf("%d",&q); for(int i=1;i<=q;i++){ ans[i]=0; query[i].Id=i; scanf("%d%d",&query[i].l,&query[i].r); } sort(query+1,query+1+q); cnt=1; for(int i=1;i<=n&&cnt<=q;i++){ int t=mp[num[i]]; if(!last[t]){ update(i,num[i]); } else{ update(last[t],-num[i]); update(i,num[i]); } last[t]=i; while(query[cnt].r==i&&cnt<=q){ ans[query[cnt].Id]=sum(query[cnt].r)-sum(query[cnt].l-1); cnt++; } } for(int i=1;i<=q;i++) printf("%I64d\n",ans[i]); } return 0; }