zoukankan      html  css  js  c++  java
  • [可持久化01Trie] BZOJ 3261 最大异或和

    给定一个非负整数序列{a},初始长度为N。

    有M个操作,有以下两种操作类型:

    1、Ax:添加操作,表示在序列末尾添加一个数x,序列的长度N+1。

    2、Qlrx:询问操作,你需要找到一个位置p,满足l<=p<=r,使得:

    a[p] xor a[p+1] xor ... xor a[N] xor x 最大,输出最大是多少。

    Input

    第一行包含两个整数 N  ,M,含义如问题描述所示。   
    第二行包含 N个非负整数,表示初始的序列 A 。 
    接下来 M行,每行描述一个操作,格式如题面所述。   

    Output

    假设询问操作有 T个,则输出应该有 T行,每行一个整数表示询问的答案。

    Sample Input

    5 5

    2 6 4 3 6

    A 1

    Q 3 5 4

    A 4

    Q 5 7 0

    Q 3 6 6

    对于测试点 1-2,N,M<=5 。 对于测试点 3-7,N,M<=80000 。 对于测试点 8-10,N,M<=300000 。 其中测试点 1, 3, 5, 7, 9保证没有修改操作。 0<=a[i]<=10^7。

    Sample Output

    4 5 6

     题意如上, 求值为 max(a[pos] \, _{xor}\, a[n] \, _{xor} \, val) \, (x <= p <= y)

    异或有前缀性质,对数组进行前缀异或处理 (下标1为0, xiabiao 2为a[1]) 

    则 a[pos] \, _{xor}\, a[n] \, _{xor} \, val  可直接将 val 与 a[n] 异或后在x, y 区间内找一个最大前缀异或值即为答案

    对于区间内最大异或值用可持久化01trie记录当前根内前缀节点和的数量

    当 sum[ tr[nto][dig] ] - sum[ tr[lto][dig] ] 时说明此区间内该节点有至少一个

    然后按正常的异或贪心gao一下即可

    代码:


    /*
        Zeolim - An AC a day keeps the bug away
    */
     
    //#pragma GCC optimize(2)
    //#pragma GCC ("-W1,--stack=128000000")
    #include <bits/stdc++.h>
    using namespace std;
    #define mp(x, y) make_pair(x, y)
    #define fr(x, y, z) for(int x = y; x < z; ++x)
    #define pb(x) push_back(x)
    #define mem(x) memset(x, 0, sizof(x))
    typedef long long ll;
    typedef unsigned long long ull;
    typedef long double ld;
    typedef std::pair <int, int> pii;
    typedef std::vector <int> vi;
    //typedef __int128 ill;
    const ld PI = acos(-1.0);
    const ld E = exp(1.0);
    const ll INF = 0x3f3f3f3f3f3f3f3f;
    const ll MOD = 386910137;
    const ull P = 13331; 
    const int MAXN = 6e5 + 10;
    
    struct trie
    {
    	int cnt, root[MAXN], tr[MAXN * 25][2], sum[MAXN * 25];
    	
    	trie() {cnt = 0;}
    	
    	void insert(int now, int last, int val) 
    	{
    		int nto, lto;
    		root[now] = nto = ++cnt;
    		lto = root[last];
    		for(int i = 23; i >= 0; --i)
    		{
    			int dig = val >> i & 1;
    			tr[nto][0] = tr[lto][0];
    			tr[nto][1] = tr[lto][1];
    			tr[nto][dig] = ++cnt, nto = cnt;
    			lto = tr[lto][dig];
    			sum[nto] = sum[lto] + 1;
    		}
    	}
    	
    	int get(int now, int last, int val)
    	{
    		int ret = 0;
    		int nto = root[now], lto = root[last];
    		for(int i = 23; i >= 0; --i)
    		{
    			int dig = val >> i & 1 ^ 1;
    			if(sum[ tr[nto][dig] ] - sum[ tr[lto][dig] ])
    				ret += (1 << i), nto = tr[nto][dig], lto = tr[lto][dig];
    			else
    				nto = tr[nto][dig ^ 1], lto = tr[lto][dig ^ 1];
    		}
    		return ret;
    	}
    }T;
    
    int arr[MAXN];
    
    int main()
    {  
        ios::sync_with_stdio(0);
        cin.tie(0); cout.tie(0);
        //freopen("d:out.txt","w",stdout);
        //freopen("d:in.txt","r",stdin);
        
    	int n, m;
    	
    	cin >> n >> m;
    	
    	++n;
    	
    	T.insert(1, 0, 0);
    	
    	for(int i = 2, t; i <= n; ++i)
    	{
    		cin >> arr[i];
    		arr[i] ^= arr[i - 1];
    		T.insert(i, i - 1, arr[i]);
    	}
    	
    	while(m--)
    	{
    		char op;
    		
    		int x, y, val;
    		
    		cin >> op;
    		
    		if(op == 'A')
    		{
    			cin >> x;
    			arr[++n] = x;
    			arr[n] ^= arr[n - 1];
    			T.insert(n, n - 1, arr[n]);
    		}
    		else
    		{
    			cin >> x >> y >> val;
    
    			cout << T.get(y, x - 1, arr[n] ^ val) << '
    ';
    		}
    	}
    
        return 0;
    }
  • 相关阅读:
    扶桑号战列舰【单调栈+线段树】
    c++ vector基本函数、排序、查找用法
    路【邻接矩阵存图找最短路】
    free【分层图最短路】
    Magic Line【坐标点排序方法】
    Stones【中石油个人赛第十七场I】
    Second Large Rectangle【单调栈】
    点坐标求三角形面积【向量差乘】
    Random Point in Triangle【随机数解决期望值问题】
    JavaScript——基础知识,开始我们的js编程之旅吧!
  • 原文地址:https://www.cnblogs.com/zeolim/p/12270346.html
Copyright © 2011-2022 走看看