http://acm.hdu.edu.cn/showproblem.php?pid=3874
今天和涂涂新学的离线算法,太牛了
大概就是先接收所有数据,然后按查询右边界排序,从左往右更新,遇到之前加过的数就删掉,因为按右边界排序,所以查询区间不断右移,删掉不会出错
View Code
#include <iostream> #include <algorithm> #include <map> using namespace std ; const int maxn=50001 ; typedef __int64 LL ; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 map <int,int> hash ; struct node{ int l,r,id ; }kk[maxn<<2] ; int a[maxn] ; LL sum[maxn<<2] ; LL ans[maxn<<2] ; void pushup(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1] ; } void update(int p,int add,int l,int r,int rt) { if(l==r) { sum[rt]+=add ; return ; } int m=(l+r)>>1 ; if(p<=m) update(p,add,lson) ; else update(p,add,rson) ; pushup(rt) ; } LL query(int L,int R,int l,int r,int rt) { if(L<=l && R>=r) return sum[rt] ; int m=(l+r)>>1 ; LL ret=0 ; if(L<=m) ret+=query(L,R,lson) ; if(R>m) ret+=query(L,R,rson) ; return ret ; } bool cmp(node a,node b) { return a.r<b.r ; } int main() { int t ; scanf("%d",&t) ; while(t--) { int n ; scanf("%d",&n) ; for(int i=1;i<=n;i++) scanf("%d",&a[i]) ; int m ; scanf("%d",&m) ; for(int i=1;i<=m;i++) { scanf("%d%d",&kk[i].l,&kk[i].r) ; kk[i].id=i ; } sort(kk+1,kk+m+1,cmp) ; hash.clear() ; memset(sum,0,sizeof(sum)) ; int r=1 ; for(int i=1;i<=m;i++) { while(r<=kk[i].r) { if(hash[a[r]]) update(hash[a[r]],-a[r],1,n,1) ; update(r,a[r],1,n,1) ; hash[a[r]]=r ; r++ ; } ans[kk[i].id]=query(kk[i].l,kk[i].r,1,n,1) ; } for(int i=1;i<=m;i++) printf("%I64d\n",ans[i]) ; } return 0 ; }