标签: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