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>

const int BUF = 10000010;
char Buf[10000010], *buf = Buf;

void read (int &now)
{
    int temp = 0;
    for (now = 0; !isdigit (*buf); ++ buf)
        if (*buf == ‘-‘)
            temp = 1;
    for (; isdigit (*buf); now = now * 10 + *buf - ‘0‘, ++ buf);
    if (temp)
        now = -now;
}

#define Max 200009

struct T_D
{
    T_D *Left, *Right;
    int size, thb[31];
};

int sum[Max][31], number[Max];
int _Total, _Swap, Count, Times;

class DuLiu_Type
{
    private :

        T_D poor[Max * 31], *Tail, *Root, *null;

        inline T_D *New ()
        {
            T_D *now = Tail ++;
            now->child[0] = now->child[1] = null;
            now->size = 0;
            return now;
        }

    public :

        DuLiu_Type ()
        {
            Tail = poor;
            null = Tail ++;
            null->child[0] = null->child[1] = null;
            null->size = 0;
            Root = New ();
        }

        void Insert (const int &key)
        {
            T_D *now = Root;
            ++ Times;
            for (int i = 30; i >= 0; -- i)
            {
                if (now->child[(key >> i) & 1] == null)
                    now->child[(key >> i) & 1] = New ();
                now = now->child[(key >> i) & 1];
                ++ now->size;
                for (int j = 0; j <= 30; ++ j)
                    now->thb[j] += (key >> j) & 1;
            }
        }

        inline void Push (const int &key)
        {
            number[++ Count] = key;
            for (int i = 0; i <= 30; ++ i)
                sum[Count][i] = sum[Count - 1][i] + ((key >> i) & 1);
        }

        inline void ReBuild ()
        {
            for (; Count; )
                this->Insert (number[Count --]);
            _Swap = _Total;
        }

        long long Find (int k)
        {
            T_D *now = Root;
            long long res = 0;
            for (int i = 30; i >= 0; -- i)
            {
                if (k == 0)
                    break;
                if (k < now->child[(_Swap >> i) & 1]->size)
                    now = now->child[(_Swap >> i) & 1];
                else
                {
                    T_D *pos = now->child[(_Swap >> i) & 1];
                    k -= pos->size;
                    for (int j = 0; j <= 30; ++ j)
                        if ((_Total >> j) & 1)
                            res += (long long)(pos->size - pos->thb[j]) << j;
                        else
                            res += (long long)pos->thb[j] << j;
                    now = now->child[(_Swap >> i) & 1 ^ 1];
                }
            }
            for (int i = 0; i <= 30; ++ i)
            {
                if (((_Total >> i) & 1) && now->thb[i] == 0)
                    res += (long long) k << i;
                if (((_Total >> i) & 1) == 0 && now->thb[i])
                    res += (long long) k << i;
            }
            return res;
        }

        long long Query (int key)
        {
            if (key <= Times)
                return this->Find (key);
            long long res = this->Find (Times);
            key -= Times;
            for (int i = 0; i <= 30; ++ i)
                if ((_Total >> i) & 1)
                    res += (long long) (key - sum[key][i]) << i;
                else
                    res += (long long) sum[key][i] << i;
            return res;
        }

        void Change (const int key)
        {
            _Total ^= key;
            return ;
        }
};

DuLiu_Type Duliu;

int main (int argc, char *argv[])
{
    fread (buf, 1, BUF, stdin);
    int N, M;
    read (N);

    int x;
    for (int i = 1; i <= N; ++ i)
    {
        read (x);
        Duliu.Push (x);
    }

    read (M);
    int y, type;
    for (; M; -- M)
    {
        read (type);
        if (type == 1)
        {
            read (x);
            Duliu.Push (x ^ _Total);
        }
        else if (type == 2)
        {
            read (x);
            read (y);
            printf ("%lld\n", Duliu.Query(y) - Duliu.Query(x - 1));
        }
        else if (type == 3)
        {
            read (x);
            Duliu.Change (x);
        }
        else
            Duliu.ReBuild ();
    }    

    return 0;
}
时间: 2024-10-21 12:34:57

LibreOJ #517. 「LibreOJ β Round #2」计算几何瞎暴力的相关文章

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

https://loj.ac/problem/517 题解 首先我们如果没有排序这个骚操作的话,可以直接记一下各个数位的前缀和,然后异或标记给全局打,查询的时候先把区间信息提取出来然后整体异或就好了. 对于排序,我们考虑对所有排好序的节点建\(trie\)树,这样即使有全局异或标记,我们也可以在\(trie\)树上完成前缀信息的查询. 然后就做完了. 代码 #include<bits/stdc++.h> #define N 200009 #define ls ch[cnt][0] #defin

LibreOJ #515. 「LibreOJ β Round #2」贪心只能过样例

二次联通门 : LibreOJ #515. 「LibreOJ β Round #2」贪心只能过样例 /* LibreOJ #515. 「LibreOJ β Round #2」贪心只能过样例 很显然 贪心方程哦不 dp方程为 f[i][j]=f[i-1][j-k*k] 但是这样的话复杂度就是O(N ^ 5) 那么就用bitset优化一下 就ok了 */ #include <iostream> #include <cstdio> #include <bitset> void

LibreOJ #514. 「LibreOJ β Round #2」模拟只会猜题意

二次联通门 : LibreOJ #514. 「LibreOJ β Round #2」模拟只会猜题意 /* LibreOJ #514. 「LibreOJ β Round #2」模拟只会猜题意 本想打个暴力找找规律 结果交上去就A了... 读入所有数 处理出前缀和 然后枚举区间长度 处理处1~n的答案 后O(1)查询即可 复杂度O(n^2 + m) */ #include <iostream> #include <cstring> #include <cstdio> voi

LibreOJ #507. 「LibreOJ NOI Round #1」接竹竿

二次联通门 : LibreOJ #507. 「LibreOJ NOI Round #1」接竹竿 /* LibreOJ #507. 「LibreOJ NOI Round #1」接竹竿 dp 记录一下前驱就好了 再随便用前缀和优化一下 O(N) */ #include <iostream> #include <cstdio> const int BUF = 100000010; char Buf[BUF], *buf = Buf; inline long long max (long

LibreOJ #525. 「LibreOJ β Round #4」多项式

二次联通门 : LibreOJ #525. 「LibreOJ β Round #4」多项式 官方题解 : /* LibreOJ #525. 「LibreOJ β Round #4」多项式 由于会有多种解 所以只需要找出一组特殊解即可 */ #include <cstdio> #include <iostream> void read (int &now) { register char c = getchar (); for (now = 0; !isdigit (c);

LibreOJ #528. 「LibreOJ β Round #4」求和

二次联通门 : LibreOJ #528. 「LibreOJ β Round #4」求和 /* LibreOJ #528. 「LibreOJ β Round #4」求和 题目要求的是有多少对数满足他们的最大公约数的质因子不超过一个 f (x) 表示有多少对数满足最大公约数中含有x^2这个因子 那么f (x) = N / x ^ 2 * M * (x ^ 2) 答案即为所有数字减去不符合要求的数字个数 但是我们发现,可能某对数字的最大公约数含有多个质数平方因子 那么在处理的时候就会重复筛去 这时我

LibreOJ #526. 「LibreOJ β Round #4」子集

二次联通门 : LibreOJ #526. 「LibreOJ β Round #4」子集 /* LibreOJ #526. 「LibreOJ β Round #4」子集 考虑一下,若两个数奇偶性相同 若同为奇数, 那加1后就是偶数, gcd的乘积就一定不是1 偶数相同 那么我们把原数中的偶数分为一个集合,奇数分为一个集合 把互相之间不符合要求的连边 那么问题就转化为了二分图求最大独立集 */ #include <cstdio> #include <iostream> #includ

LibreOJ #6191. 「美团 CodeM 复赛」配对游戏

二次联通门 : LibreOJ #6191. 「美团 CodeM 复赛」配对游戏 /* LibreOJ #6191. 「美团 CodeM 复赛」配对游戏 概率dp 不是很懂为什么这样做... */ #include <cstdio> #include <iostream> const int BUF = 12312312; char Buf[BUF], *buf = Buf; inline void read (int &now) { for (now = 0; !isdi

loj #6091. 「Codeforces Round #418」幻想特快

#6091. 「Codeforces Round #418」幻想特快 1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 #include<queue> 6 using namespace std; 7 #define maxn 10000 8 int n,a[maxn],b[maxn],p[maxn],nxt1,nxt2,tot,