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;
}

 

posted @ 2013-08-20 20:03  冰鸮  阅读(175)  评论(0)    收藏  举报