HDU 3333 Turing Tree
离线操作,区间求和(线段树或树状数组)。
将询问按照$q[i].R$从小到大进行排序,然后逐个更新$a[i]$,如果之前$a[i]$不存在,那么直接更新进去,如果之前$a[i]$存在,那么把之前位置的$a[i]$删掉,更新成现在位置。这样操作就能保证:$i$位置更新完毕之后,存在的数都是不同的,并且都是最靠近$i$的。
如果某个$a[i]$更新完之后,发现有$q[i].R==i$,那么这些询问已经可以得出答案了。最后按照输入的顺序输出即可。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<iostream> using namespace std; typedef long long LL; const double pi=acos(-1.0),eps=1e-8; void File() { freopen("D:\\in.txt","r",stdin); freopen("D:\\out.txt","w",stdout); } const int maxn=30010; int T,n; LL a[maxn],c[maxn]; struct X { int id,L,R;LL ans; }q[100010]; bool cmp(X a,X b) { return a.R<b.R; } bool cmp1(X a,X b) { return a.id<b.id; } int lowbit(int x) { return x&(-x); } void update(int p,LL v) { while(p<=n) c[p]=c[p]+v,p=p+lowbit(p); } LL sum(int p) { LL res=0; while(p>0) res=res+c[p],p=p-lowbit(p); return res; } int main() { scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); map<LL,int>m; int Q; scanf("%d",&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); int p=1; memset(c,0,sizeof c); for(int i=1;i<=n;i++) { int h=m[a[i]]; if(h!=0) update(h,-a[i]); update(i,a[i]); m[a[i]]=i; while(p<=Q&&q[p].R==i) q[p].ans=sum(q[p].R)-sum(q[p].L-1), p++; } sort(q+1,q+1+Q,cmp1); for(int i=1;i<=Q;i++) printf("%lld\n",q[i].ans); } return 0; }