HDU 3874 Necklace 树状数组

 题意:求区间内不同的数的和

离线处理,按查询右端点从小到大排序,从左往右扫一遍。

记录每个数出现的上一个位置,如果该数之前没有出现过,就加上,否则就在上一个位置减去。

 

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <algorithm>



#define LL long long int



using namespace std;



const int MAXN = 1000100;



struct node

{

    int id;

    int l, r;

};



int N, Q;

int pre[MAXN];      //某数之前出现的位置

LL sum[50100];

LL val[50100];

int maxL;

node D[200100];

LL ans[200100];



int lowbit( int x )

{

    return x&(-x);

}



LL query( int x )

{

    LL res = 0;

    while ( x > 0 )

    {

        res += sum[x];

        x -= lowbit(x);

    }

    return res;

}



void update( int x, int val )

{

    while ( x <= N )

    {

        sum[x] += val;

        x += lowbit(x);

    }

    return;

}



bool cmp( node a, node b )

{

    if ( a.r != b.r ) return a.r < b.r;

    else if ( a.l != b.r ) return a.l < b.l;

    return a.id < b.id;

}



int main()

{

    int T;

    scanf( "%d", &T );

    while ( T-- )

    {

        scanf( "%d", &N );

        for ( int i = 1; i <= N; ++i )

            scanf( "%I64d", &val[i] );



        scanf( "%d", &Q );

        for ( int i = 0; i < Q; ++i )

        {

            D[i].id = i;

            scanf( "%d%d", &D[i].l, &D[i].r );

        }



        memset( pre, -1, sizeof(pre) );

        memset( sum,  0, sizeof(sum) );



        sort( D, D + Q, cmp );



        int cur = 1;

        for ( int i = 0; i < Q; ++i )

        {

            while ( cur <= D[i].r )

            {

                if ( pre[ val[cur] ] != -1 )

                    update( pre[ val[cur] ], -val[cur] );



                update( cur, val[cur] );

                pre[ val[cur] ] = cur;

                ++cur;

            }

            ans[ D[i].id ] = query( D[i].r ) - query( D[i].l - 1 );

        }

        for ( int i = 0; i < Q; ++i )

            printf( "%I64d\n", ans[i] );



    }

    return 0;

}

 

你可能感兴趣的:(树状数组)