题意:给出一组序列,问某个区间内序列的和,跟普通求和不同的是,要求值相同的元素只能算一次。
树状数组 Or 线段树 :刚开始以为和前两道题目思路差不多,就考虑了考虑,离散化写了起来!!但中间突感有的数据没有处理!!于是考虑二分+离散处理query区间的数据!!!
于是乎:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=166612;///我数组开到30000+不对,在后面加一个0就对了。。表示想不清楚! int t,n,m,a[maxn],b[maxn],pre[maxn],cnt; __int64 A[maxn],c[maxn]; struct node { int l,r,id; }p[maxn]; int cmp(node a,node b) { return a.r<=b.r; } int lowbit(int i) { return (i&(-i)); } void add(int i,int d) { while(i<=n) { c[i]+=d; i+=lowbit(i); } } __int64 sum(int i) { __int64 ret=0; while(i) { ret+=c[i]; i-=lowbit(i); } return ret; } int bin(int idx,int num) { int l=0,mid,r=num-1; while(l<=r) { mid=(l+r)>>1; if(a[mid]==idx)return mid; if(a[mid]>idx) r=mid-1; else l=mid+1; } return -1; } int main() { int i,j,l,r; scanf("%d",&t); while(t--) { scanf("%d",&n); //memset(A,0,sizeof(A)); // memset(c,0,sizeof(c)); // memset(pre,0,sizeof(pre)); for(i=0;i<=n;i++)A[i]=c[i]=0,pre[i]=0; cnt=0; for(i=1;i<=n;i++) { scanf("%d",&b[i]); a[cnt++]=b[i]; } sort(a,a+cnt); cnt=unique(a,a+cnt)-a; scanf("%d",&m); for(i=1;i<=m;i++) { scanf("%d%d",&p[i].l,&p[i].r); p[i].id=i; } sort(p+1,p+m+1,cmp); for(j=1,i=1;i<=n;i++) { int id=bin(b[i],cnt); if(pre[id]) add(pre[id],-b[i]); add(i,b[i]); pre[id]=i; while(j<=m&&p[j].r==i) { A[p[j].id]=sum(p[j].r)-sum(p[j].l-1); j++; } } for(i=1;i<=m;i++) { printf("%I64d\n",A[i]); } } return 0; } /* 2 3 1 1 4 2 1 2 2 3 5 1 1 2 1 3 3 1 5 2 4 3 5 */