Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3847 Accepted Submission(s): 1306
题目描述: 求给定一个序列中某段子区间的相异数的和。
要求相异数的和,那就把相同的数去掉就行,可是由于查询的区间不确定,假设要查被删数之前包含被删数的区间的和,就不好办了。
所以我们首先读入所有的查询,然后在建立树状数组的过程中可以一次回答以i结尾的数之前的所有查询,如果有重复的就删掉,
因为比i小的以它结尾所有的查询都存下。由于要按顺序输出它的结果,所以我们给每个查询操作编号,又由于要从小到大回答以i结尾
的所有查询,所以我们采用一个结构体,成员变量分别是L,R,ID;以R来对结构体排序,将结果存入map<int,int > s;
s[ID]中,采用二维数组浪费空间,采用map进行映射.
最后一点要注意的是c数组的大小要是n的最大值×4;
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <algorithm> #include <map> #define maxn 55555*4 #define LL long long #define inf 0x3f3f3f3f3f3f3f3f3f3f #define lowbit(x) x & (-x) using namespace std; //int visit[maxn]; //int VISIT[maxn]; map <LL,LL > visit; map <LL ,LL > VISIT; LL A[maxn]; int n,cnt; struct node { int L,R,id; }; node Q[maxn]; LL c[maxn]; LL ans[maxn]; void init() { memset(c,0,sizeof(c)); //memset(visit,0,sizeof(visit)); //memset(VISIT,0,sizeof(VISIT)); visit.clear(); VISIT.clear(); cnt=0; } LL sum(int x) { LL ret=0; while(x>0) { ret+=c[x]; x-=(x&(-x) ); } return ret; } void add(int x,LL d) { while(x<=n) { c[x]+=d; x+=(x& (-x) ); } } void solve() { for(int i=1;i<=n;i++) { if(visit[A[i]]!=0) { add(visit[A[i]],-A[i]); } visit[A[i]]=i; add(i,A[i]); if(VISIT[i]!=0) { for(int j=1;j<=VISIT[i];j++) { cnt++; ans[Q[cnt].id]=sum(Q[cnt].R)-sum(Q[cnt].L-1); //printf("%lld\n",ans[Q[cnt].id]); } } } } bool cmp(node a,node b) { if(a.R==b.R) return a.L<b.L; else return a.R<b.R; } int main() { //freopen("test.txt","r",stdin); int t,q; scanf("%d",&t); while(t--) { init(); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld",&A[i]); scanf("%d",&q); for(int i=1;i<=q;i++) { scanf("%d%d",&Q[i].L,&Q[i].R); Q[i].id=i; // printf("%d\n",Q[i].id); ++VISIT[Q[i].R]; } sort(Q+1,Q+q+1,cmp); /* for(int i=1;i<=q;i++) { printf("%d\n",Q[i].id); }*/ solve(); for(int i=1;i<=q;i++) { printf("%lld\n",ans[i]); } } return 0; }