• [LOJ#517]. 「LibreOJ β Round #2」计算几何瞎暴力[trie]


    题意

    题目链接

    分析

    • 记操作异或和为 (tx) ,最后一次排序时的异或和为 (ax) ,每个数插入时的 (tx) 记为 (b)

    • 我们发现,一旦数列排序,就会变得容易操作。

    • 对于新加入的数字用一个前缀和数组维护每一位为 1 的个数(每个数保证在 (xor​) 当前 (tx​) 之后能够得到真实结果)。对于进行过排序的数字用 trie 维护(每个数用 (a_i xor b_i​) 表示)。

    • 查找 trie 上的数字在 (xor ax) 排序后的前 (k) 个值中每一位有多少个1,如果 (ax) 对应位是 1 就先走右子树。

    • 如果要进行新的排序,就将没插入 trie 的数字以 (a_i xor b_i) 插入到 trie 中即可。

    • 时间复杂度 (O(nlogn))

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    #define go(u) for(int i = head[u], v = e[i].to; i; i=e[i].lst, v=e[i].to)
    #define rep(i, a, b) for(int i = a; i <= b; ++i)
    #define pb push_back
    #define re(x) memset(x, 0, sizeof x)
    inline int gi() {
        int x = 0,f = 1;
        char ch = getchar();
        while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar();}
        while(isdigit(ch)) { x = (x << 3) + (x << 1) + ch - 48; ch = getchar();}
        return x * f;
    }
    template <typename T> inline bool Max(T &a, T b){return a < b ? a = b, 1 : 0;}
    template <typename T> inline bool Min(T &a, T b){return a > b ? a = b, 1 : 0;}
    const int N = 2e5 + 7;
    int n, tp, m;
    int a[N], num[N];
    int ax, totx;
    int f[N][33], res[33];
    namespace Trie {
    	const int Nd = N * 33;
    	int ch[Nd][2], ndc = 1, son[Nd], sum[Nd][33];
    	void insert(int x) {
    		int u = 1;
    		for(int i = 30; ~i; --i) {
    			rep(j, 0, i + 1) if(x >> j & 1) ++sum[u][j];
    			++son[u];
    			int c = x >> i & 1;
    			if(!ch[u][c]) ch[u][c] = ++ndc;
    			u = ch[u][c];
    		}
    		if(x & 1)
    			++sum[u][0];
    		++son[u];
    	}
    	void query(int u, int i, int k) {
    		if(!u || !k || i < 0) return;
    		int c = ax >> i & 1;
    		if(son[ch[u][c]] >= k) query(ch[u][c], i - 1, k), res[i] += c * k;
    		else {
    			rep(j, 0, i) res[j] += sum[ch[u][c]][j];
    			query(ch[u][c ^ 1], i - 1, k - son[ch[u][c]]);
    			res[i] += (c ^ 1) * (k - son[ch[u][c]]);
    		}
    	}
    	LL query(int l, int r) {
    		LL ans = 0;
    		re(res);
    		query(1, 30, r);
    		rep(j, 0, 30)
    		ans += 1ll * (totx >> j & 1 ? r - res[j] : res[j]) << j;
    		
    		re(res);
    		query(1, 30, l - 1);
    		rep(j, 0, 30)
    		ans -= 1ll * (totx >> j & 1 ? l - 1 - res[j] : res[j]) << j;
    		return ans;
    	}
    }
    
    LL query(int l, int r) {
    	LL ans = 0;
    	memcpy(res, f[r], sizeof res);
    	rep(j, 0, 30)
    	ans += 1ll * (totx >> j & 1 ? r - res[j] : res[j]) << j;
    	memcpy(res, f[l - 1], sizeof res);
    	rep(j, 0, 30)
    	ans -= 1ll * (totx >> j & 1 ? l - 1 - res[j] : res[j]) << j;
    	return ans;
    }
    int main() {
    	n = gi();
    	rep(i, 1, n) {
    		int x = gi();
    		num[++tp] = x;
    		rep(j, 0, 30) f[tp][j] = f[tp - 1][j] + (x >> j & 1);
    	}
    	m = gi();
    	while(m--) {
    		int opt = gi();
    		if(opt == 1) {
    			int x = gi();
    			num[++tp] = x ^ totx;
    			rep(j, 0, 30) f[tp][j] = f[tp - 1][j] + ((x ^ totx) >> j & 1);
    		}
    		if(opt == 2) {
    			int l = gi(), r = gi(), k = Trie::son[1];
    			if(r <= k)
    				printf("%lld
    ", Trie::query(l, r));
    			else if(l <= k) 
    				printf("%lld
    ", query(1, r - k) + Trie::query(l, k));
    			else 
    				printf("%lld
    ", query(l - k, r - k));
    		}
    		if(opt == 3) {
    			totx ^= gi();
    		}
    		if(opt == 4) {
    			for(; tp; --tp) Trie::insert(num[tp]);
    			ax = totx;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    ionic环境搭建
    C# Enum Type
    【IOS】3. OC 类声明和实现
    【IOS】2.基础
    【IOS】1.学前准备
    win8, VS2013 .NET 4.5在哪找svcutil.exe?
    【你吐吧c#每日学习】11.10 C# Data Type conversion
    【你吐吧c#每日学习】10.30 C#Nullable Types
    【你吐吧c#每日学习】10.29 C#字符串类型&Common operators
    给三个int,判断是否可构成三角形算法
  • 原文地址:https://www.cnblogs.com/yqgAKIOI/p/10550740.html
Copyright © 2020-2023  润新知