hdu 3333 树状数组

            我不得不写文章夸奖一下自己,调试能力和写代码能力越来越强了。自己写的代码,一wa之后将c数组改成__int64就过了。对数字的敏感程度越来越强。做了这么多次多校,感觉敏感度很重要,还有数学的思辨能力。这些能力很生活。

           言归正传。此题的作法是离线的。将所有的询问按右端点排序(为什么这样? 因为处理的时候我们从左向右处理,处理到i这个位置的时候,前面都已经处理好了(处理好了的意思是我们将所有的不唯一的值都搞成唯一(搞成唯一就是只有一个在i之前(包括i这个位置),并且尽量靠近i),这样求和的时候就不会重复了。),只要求和就行了。)。右端点相同的批量处理,将答案存下来,最后以O(1)直接得出答案。

           这题还要离散化一下,目的是标记之前有没有出现过这个值。

还有一种是线段树的作法,思路是一模一样的,就是用线段树实现而已。

/*
Pro: 0

Sol:

date:12/08/17
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <vector>
#define maxn 50000
using namespace std;
int t,n,a[maxn],Q;
struct query{
    int L,R,id;
    bool operator < (const query& cmp) const{
        return R < cmp.R;//按照右端点排序
    }
}q[100100];
int tp[maxn],last[maxn];
__int64 ans[100100],c[maxn];
int lowbit(int x) {return x & (-x);}
void modify(int pos, int val){
    while(pos <= n){
        c[pos] += (__int64)val;
        pos += lowbit(pos);
    }
}
__int64 getsum(int pos){
    __int64 sum = 0;
    while(pos){
        sum += (__int64)c[pos];
        pos -= lowbit(pos);
    }
    return sum;
}
int bin(int low,int high,int key,int fi[]){
    while(low < high){
        int mid = (low + high) >> 1;
        if(fi[mid] < key) low = mid + 1;
        else high = mid;
    }
    return low;
}
int main(){
    scanf("%d",&t);
    for(int ca = 1; ca <= t; ca ++){
        scanf("%d",&n);
        for(int i = 1; i <= n; i ++){
            scanf("%d",&a[i]);
            tp[i] = a[i];//离散化是为了标记这个数是否出现过
//            c[i] = a[i];
        }
        sort(tp + 1, tp + 1 + n);
        scanf("%d",&Q);
        for(int i = 1; i <= Q; i ++){
            scanf("%d",&q[i].L);
            scanf("%d",&q[i].R);
            q[i].id = i;
        }
        sort(q + 1, q + Q + 1);
        memset(last,0,sizeof(last));
        memset(c,0,sizeof(c));//每次都得memset一下。
        int qsub = 1;
        for(int i = 1; i <= n; i ++){
            int x = bin(1,n,a[i],tp);
            if(last[x]){modify(last[x],-a[i]); }

            modify(i,a[i]);last[x] = i;

            while(q[qsub].R == i && qsub <= Q){
                __int64 tmp = getsum(q[qsub].R) - getsum(q[qsub].L - 1);
                ans[q[qsub].id] = tmp;
                qsub ++;
            }
//            for(int j = 1; j <= 5; j ++)
//                cout << c[j] << "  ";   cout << endl;
        }
        for(int i = 1; i <= Q; i ++){
            printf("%I64d\n",ans[i]);
        }
    }
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值