HDU 3854 Glorious Array 树状数组

一组数据:

2
9 10 2
2 3 1 4 2 5 1 3 4
0 1 0 1 1 1 1 1 0
1
0 4
1
0 4
1
0 5
0 7
1
0 2
1
5 10 2
1 1 1 1 1
0 1 0 1 0
1
0 3
1
0 3
1
0 1
0 4
0 5
0 2
1

答案:

16
16
16
16
15
6
6
6
6

以第一组为例:

2 3 1 4 2 5 1 3 4

以小于K的数为分界,将数列分成几段。

对于每个数字,记录它所在段的左端点和右端点,据此求出修改前的合法对数sum。

对于每个修改,查看当前修改发生在哪一段,该修改对sum产生了怎样的影响,修改sum即可。

树状数组C[i]记录区间[1, i]共有多少个白点。

注意修改发生在段内和段端点处要分开考虑。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>

#define LL long long int

using namespace std;

const int MAXN = 100100;

int N, Q, K;
int C[MAXN];         //1-i之间有多少个白点
int val[MAXN];
int left[MAXN];
int right[MAXN];
LL sum;
bool color[MAXN];

int lowbit( int x )
{
    return x & (-x);
}

void Update( int x, int val )
{
    while ( x <= N )
    {
        C[x] += val;
        x += lowbit(x);
    }
    return;
}

int Query( int x )
{
    if ( x == 0 ) return 0;
    int res = 0;
    while ( x > 0 )
    {
        res += C[x];
        x -= lowbit(x);
    }
    return res;
}

void init()
{
    int pre = 0;
    for ( int i = 1; i <= N; ++i )
    {
        left[i] = pre;
        if ( val[i] < K )
            pre = i;
    }

    pre = N + 1;
    for ( int i = N; i > 0; --i )
    {
        if ( val[i] < K )
            pre = i;
        right[i] = pre;
    }
    return;
}

int main()
{
    //freopen( "in.txt", "r", stdin );
    int T;
    scanf( "%d", &T );
    while ( T-- )
    {
        memset( C, 0, sizeof(C) );
        scanf( "%d%d%d", &N, &Q, &K );

        for ( int i = 1; i <= N; ++i )
            scanf("%d", &val[i] );

        for ( int i = 1; i <= N; ++i )
        {
            int a;
            scanf("%d", &a );
            if ( a == 0 )
            {
                Update( i, 1 );
                color[i] = true;
            }
            else color[i] = false;
        }
        init();

        sum = 0;
        for ( int i = 1; i <= N; ++i )
        if ( val[i] < K )
        {
            LL white = Query(i) - Query( left[i] );
            LL black = i - left[i] - white;
            LL houW = Query(N) - Query(i - 1);
            LL houB = N - i + 1 - houW;
            sum += white * houB + black * houW;
        }

        for ( int i = 0; i < Q; ++i )
        {
            int op;
            scanf( "%d", &op );
            if ( op == 0 )
            {
                int v;
                scanf( "%d", &v );

                LL preW, preB, aftW, aftB;
                if ( val[v] >= K )
                {
                    preW = Query( left[v] );
                    preB = left[v] - preW;
                    aftW = Query(N) - Query( right[v] - 1 );
                    aftB = N - right[v] + 1 - aftW;
                }
                else
                {
                    preW = Query( v - 1 );
                    preB = v - 1 - preW;
                    aftW = Query(N) - Query(v);
                    aftB = N - v - aftW;
                }

                if ( color[v] )  //之前是白的
                {
                    sum = sum - preB - aftB + preW + aftW;
                    Update( v, -1 );
                }
                else             //之前是黑的
                {
                    sum =  sum + preB + aftB - preW - aftW;
                    Update( v, 1 );
                }
                color[v] = !color[v];
            }
            else
                printf( "%I64d\n", sum );
        }
    }
    return 0;
}

 

posted @ 2013-08-30 21:03  冰鸮  阅读(257)  评论(0编辑  收藏  举报