Turing Tree(数状数组)

转自:http://blog.csdn.net/acm_baihuzi/article/details/46861109




Sample Output
   
   
1 5 6 3 6
 

Statistic |  Submit |  Back

题意:求一个区间内不重复数字的和,例如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 maxn 30010
#define M 100010
#define ll long long
using namespace std;
int n,t,q;
int a[maxn],Rl[maxn],Rr[maxn];
map<int,int>mp;
struct node {
    int id;  
    int l,r;  
} Q[M];

ll tree[maxn],ans[M];
  
int lowbit(int x){
	return x&-x;
}

bool cmp(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) {  
        tree[i]+=v;  
        i+=lowbit(i);  
    }  
}

ll getsum(int i) {
    ll s=0;
    while(i>0) {  
        s+=tree[i];  
        i-=lowbit(i); 
    }
    return s;  
}  
int main() {  
	int i,j,k;
	scanf("%d",&t); 
    while(t--) {
        cin>>n; 
        for(i=1;i<=n; i++)scanf("%d",&a[i]);  
        cin>>q;
        for(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);
        memset(tree,0,sizeof tree); 
        memset(Rl,0,sizeof Rl);
        memset(Rr,0,sizeof Rr);
        int f=1;  
        Rl[Q[f].r]=f;
        Rr[Q[f].r]=f;
        for(k=2; k<=q;) {
            while(Q[f].r==Q[k].r&&k<=q)k++;
            Rl[Q[f].r]=f;
            Rr[Q[f].r]=k-1;
            f=k;
        }
        mp.clear();  
        for(i=1; i<=n; i++) {  
            if(!mp[a[i]]) {  
                add(i,a[i]);  
                mp[a[i]]=i;  
            } else {  
                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 ss=getsum(i);  
            for(j=L; j<=R; j++) {  
                ll sss=ss;  
                sss-=getsum(Q[j].l-1);  
                ans[Q[j].id]=sss;  
            }  
        }  
        for(i=1; i<=q; i++) {  
            printf("%I64d\n",ans[i]);  
        }
    }
    return 0;  
}  



Sample Output
    
    
1 5 6 3 6
 

Statistic |  Submit |  Back
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值