标签:hdu 3333 turing tree 树状数组 离线操作
2 3 1 1 4 2 1 2 2 3 5 1 1 2 1 3 3 1 5 2 4 3 5
1 5 6 3 6
题意:求一个区间内不重复数字的和,例如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 N 30010 #define M 100010 #define ll long long using namespace std; int n,t,q; int a[N],Rl[N],Rr[N]; map<int,int>mp;///记录上一次出现的位置 struct node { int id; int l,r; } Q[M]; ll bit[N],as[M]; bool cmp_1(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) { bit[i]+=v; i+=i&-i; } } ll getsum(int i) { ll s=0; while(i>0) { s+=bit[i]; i-=i&-i; } return s; } int main() { //freopen("test.in","r",stdin); cin>>t; while(t--) { cin>>n; for(int i=1; i<=n; i++)scanf("%d",&a[i]); cin>>q; for(int 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_1); memset(bit,0,sizeof bit); memset(Rl,0,sizeof Rl); memset(Rr,0,sizeof Rr); ///预处理右区间相同的左右区间 int f=1; Rl[Q[f].r]=f; Rr[Q[f].r]=f; for(int ii=2; ii<=q;) { while(Q[f].r==Q[ii].r&&ii<=q)ii++; Rl[Q[f].r]=f; Rr[Q[f].r]=ii-1; f=ii; } mp.clear(); for(int i=1; i<=n; i++) { ///前面没出现过 if(!mp[a[i]]) { add(i,a[i]); mp[a[i]]=i; } else { ///出现过的话在当前这个位置加上a[i] ///在前面出现的位置减去a[i] 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 ans=getsum(i); for(int j=L; j<=R; j++) { ll ans_2=ans; ans_2-=getsum(Q[j].l-1); as[Q[j].id]=ans_2; } } for(int i=1; i<=q; i++) { printf("%I64d\n",as[i]); } } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
hdu 3333 Turing Tree(树状数组离线操作)
标签:hdu 3333 turing tree 树状数组 离线操作
原文地址:http://blog.csdn.net/acm_baihuzi/article/details/46861109