LibreOJ #517. 「LibreOJ β Round #2」计算几何瞎暴力

二次联通门 : LibreOJ #517. 「LibreOJ β Round #2」计算几何瞎暴力

 

 

 

 

/*
    LibreOJ #517. 「LibreOJ β Round #2」计算几何瞎暴力 
 
    叫做计算几何
    实则毒瘤数据结构

    看到xor后
    考虑Trie树
    Trie树的每一个节点保存的是以当前子树中每个二进制位的个数


    给Trie打一个全局xor标记,如果标记这一位是1,就交换它的两个儿子
     
    另外维护一个前缀和
       前缀和存的是没sort过的值的和
    Trie维护的是sort之后的值

    1操作直接在前缀和后加就好
    2操作在前缀和和Trie树中一起查
    
*/
#include <cstdio>
#include <iostream>
#define rg register
const int BUF = 10000010; char Buf[BUF], *buf = Buf; typedef long long LL;
inline void read (int &n)
{
    bool temp = false;
    for (n = 0; !isdigit (*buf); ++ buf) if (*buf == '-') temp = true;
    for (; isdigit (*buf); n = n * 10 + *buf - '0', ++ buf);
    if (temp) n = -n;
}
#define Max 200009
struct T_D { T_D *c[2]; int s, thb[31]; }; int s[Max][31], v[Max];
int _T, _S, C, T;
class Trie
{
    private : T_D poor[Max * 31], *Tail, *Root, *null;
    private :      
        inline T_D *New ()
        { T_D *now = Tail ++; now->c[0] = now->c[1] = null, now->s = 0; return now; }
    public :
        Trie ()
        {
            Tail = poor, null = Tail ++, null->c[0] = null->c[1] = null;
            null->s = 0, Root = New ();
        }
        void Insert (const int &k)
        {
            T_D *n = Root; ++ T;
            for (rg int i = 30, j; i >= 0; -- i)
            {
                if (n->c[(k >> i) & 1] == null) n->c[(k >> i) & 1] = New ();
                n = n->c[(k >> i) & 1], ++ n->s;
                for (j = 0; j <= 30; ++ j) n->thb[j] += (k >> j) & 1;
            }
        }
        inline void P (const int &key)
        {
            v[++ C] = key;
            for (rg int i = 0; i <= 30; ++ i) s[C][i] = s[C - 1][i] + ((key >> i) & 1);
        }
        inline void ReBuild () { for (; C; Insert (v[C --])); _S = _T; }
        LL Find (int k)
        {
            T_D *n = Root; LL r = 0; rg int i, j;
            for (i = 30; i >= 0; -- i)
            {
                if (k == 0) break;
                if (k < n->c[(_S >> i) & 1]->s) n = n->c[(_S >> i) & 1];
                else
                {
                    T_D *p = n->c[(_S >> i) & 1]; k -= p->s;
                    for (j = 0; j <= 30; ++ j)
                        if ((_T >> j) & 1) r += (LL) (p->s - p->thb[j]) << j;
                        else r += (LL) p->thb[j] << j;
                    n = n->c[(_S >> i) & 1 ^ 1];
                }
            }
            for (i = 0; i <= 30; ++ i)
            {
                if (((_T >> i) & 1) && n->thb[i] == 0) r += (LL) k << i;
                if (((_T >> i) & 1) == 0 && n->thb[i]) r += (LL) k << i;
            }
            return r;
        }
        LL Q (int k)
        {
            if (k <= T) return Find (k); LL r = Find (T); k -= T;
            for (rg int i = 0; i <= 30; ++ i)
                if ((_T >> i) & 1) r += (LL) (k - s[k][i]) << i;
                else r += (LL) s[k][i] << i;
            return r;
        }
        void Cg (const int key) { _T ^= key; return ; }
} D;
int main (int argc, char *argv[])
{
    fread (buf, 1, BUF, stdin); int N, M, x, t, y; read (N); rg int i;
    for (i = 1; i <= N; ++ i) read (x), D.P (x);
    for (read (M); M; -- M)
    {
        read (t);
        if (t == 1) read (x), D.P (x ^ _T);
        else if (t == 3)
            read (x), read (y), printf ("%I64d\n", D.Q(y) - D.Q(x - 1));
        else if (t == 4) read (x), D.Cg (x);
        else D.ReBuild ();
    }    
    return 0;
}

 

转载于:https://www.cnblogs.com/ZlycerQan/p/7601971.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值