HDU 4288 Coder ( 离散化 + 离线 + 线段树 )

这题跟ZOJ 3606的解题思路很相似。

 题意:有3中操作:1.向集合中增加一个数x(1≤x≤1e9);2.从集合中删去一个数x(保证这个数存在);3.查询集合中所有位置满足i%5==3的数a[i]的和,集合中的数按升序排列。给你一共N个操作,输出每次查询的和。

做法:因为操作只有10^5个,所以将所有查询中的数保存下来,排序之后离散化。每个数对应一个“位置”,通过标记这个“位置”是否已用来表示该数是否在集合中。

线段树节点记录两个信息:

cnt:这一段“位置”中含有多少个数,pushUp的时候cnt[rt] = cnt[ rt << 1 ] + cnt[ rt << 1 | 1 ];

sum[5]:sum[i]表示这个区间中,从左到右编号,位置模5为i的所有数的和。

pushUp的时候,sum[rt][i] = sum[lc][i], sum[rt][ (i+cnt[lc])%5 ]+= sum[rc][i]

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <algorithm>



#define LL long long int

#define lson l, m, rt << 1

#define rson m + 1, r, rt << 1 | 1

#define lc rt << 1

#define rc rt << 1 | 1



using namespace std;



const int MAXN = 100100;





struct Qry

{

    int op;

    int val;

} qq[MAXN];



struct node

{

    LL sum[5];

    int cnt;

};



int Q;

int num[MAXN];

int cnt;

node Tr[ MAXN << 2 ];



void build( int l, int r, int rt )

{

    for ( int i = 0; i < 5; ++i ) Tr[rt].sum[i] = 0;

    Tr[rt].cnt = 0;



    if ( l == r ) return;

    int m = ( l + r ) >> 1;

    build( lson );

    build( rson );

    return;

}



void PushUp( int rt )

{

    Tr[rt].cnt = Tr[lc].cnt + Tr[rc].cnt;

    for ( int i = 0; i < 5; ++i ) Tr[rt].sum[i] = Tr[lc].sum[i];

    for ( int i = 0; i < 5; ++i ) Tr[rt].sum[ (i+Tr[lc].cnt)%5 ] += Tr[rc].sum[i];

    return;

}



void Update( int x, int op, int l, int r, int rt )

{

    if ( l == x && x == r )

    {

        for ( int i = 0; i < 5; ++i ) Tr[rt].sum[i] = 0;

        if ( op == 1 )

        {

            Tr[rt].cnt = 1;

            Tr[rt].sum[1] = num[x];

        }

        else if ( op == 2 ) Tr[rt].cnt = 0;

        return;

    }

    int m = ( l + r ) >> 1;

    if ( x <= m ) Update( x, op, lson );

    else Update( x, op, rson );

    PushUp( rt );

    return;

}



int main()

{

    while ( scanf( "%d", &Q ) == 1 )

    {

        cnt = 1;

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

        {

            char tmp[8];

            scanf( "%s", tmp );

            if ( tmp[0] == 'a' )

            {

                qq[i].op = 1;

                scanf( "%d", &qq[i].val );

                num[cnt++] = qq[i].val;

            }

            else if ( tmp[0] == 'd' )

            {

                qq[i].op = 2;

                scanf( "%d", &qq[i].val );

                num[cnt++] = qq[i].val;

            }

            else qq[i].op = 3;

        }



        sort( num + 1, num + cnt );

        cnt = unique( num + 1, num + cnt ) - num;

        build( 1, cnt - 1, 1 );



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

        {

            if ( qq[i].op == 3 )

                printf( "%I64d\n", Tr[1].sum[3] );

            else

            {

                int x = lower_bound( num + 1, num + cnt, qq[i].val ) - num;

                Update( x, qq[i].op, 1, cnt - 1, 1 );

            }

        }

    }

    return 0;

}

 

你可能感兴趣的:(code)