zoukankan      html  css  js  c++  java
  • BZOJ2741 【FOTILE模拟赛】L 【可持久化trie + 分块】

    题目

    FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和。
    即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r。
    为了体现在线操作,对于一个询问(x,y):
    l = min ( ((x+lastans) mod N)+1 , ((y+lastans) mod N)+1 ).
    r = max ( ((x+lastans) mod N)+1 , ((y+lastans) mod N)+1 ).
    其中lastans是上次询问的答案,一开始为0。

    输入格式

    第一行两个整数N和M。
    第二行有N个正整数,其中第i个数为Ai,有多余空格。
    后M行每行两个数x,y表示一对询问。

    输出格式

    共M行,第i行一个正整数表示第i个询问的结果。

    输入样例

    3 3

    1 4 3

    0 1

    0 1

    4 3

    输出样例

    5

    7

    7

    提示

    HINT

    N=12000,M=6000,x,y,Ai在signed longint范围内。

    题解

    区间异或和最大,转化为两个前缀和

    多次询问不同区间,用可持久化trie树

    但每次要任意选出两个数,而常规的trie树只支持一个数询问区间和它的最大异或值,不能处理区间内任意两个数异或和最大值
    何破?

    我们不可能每次询问(O(n^2logn))枚举其中一个数
    那就预处理!
    如果我们能预处理出每个区间异或最大值,就是(O(n^2logn))预处理,(O(1))查询

    能不能均摊一下?
    分块!
    我们只预处理每个块头到其后面所有位置的数异或的最大值
    具体的,设(f[i][j])表示(i)块开头位置到(j)中所有数异或的最大值,记块头为(u),则(f[i][j])即为区间([u,j])的答案
    算出(f[i][j])只需要枚举每个(j)就可以了
    具体地,(f[i][j] = max(f[i][j - 1],query(j,区间[u,j - 1])))

    那么每次询问的时候,对于(l)之后的第一个块头(u),可以得到出后面的答案(f[u][r])
    所以我们只需要计算区间([l,u - 1])的数与其后面的数的最大异或值
    这个区间大小不会超过(sqrt{n}),所以可以直接统计

    总的复杂度(O(nsqrt{n}logn))
    【坑点,给出的x,y可能超过int范围】

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #define LL long long int
    using namespace std;
    const int maxn = 12005,Bit = 31,maxm = 6000000,INF = 100000000;
    inline LL read(){
    	LL out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    LL n,m,A[maxn],sum[maxn],bin[40];
    LL f[200][maxn],block[maxn],B,lans;
    struct trie{
    	int ch[maxm][2],sum[maxm],rt[maxn],cnt;
    	int ins(int pre,int x){
    		int tmp,u;
    		tmp = u = ++cnt;
    		for (int i = Bit; i >= 0; i--){
    			ch[u][0] = ch[pre][0];
    			ch[u][1] = ch[pre][1];
    			sum[u] = sum[pre] + 1;
    			LL t = x & bin[i]; t >>= i;
    			pre = ch[pre][t];
    			u = ch[u][t] = ++cnt;
    		}
    		sum[u] = sum[pre] + 1;
    		return tmp;
    	}
    	LL query(int u,int v,int x,int dep){
    		if (dep < 0) return 0;
    		LL t = x & bin[dep]; t >>= dep;
    		if (sum[ch[u][t ^ 1]] - sum[ch[v][t ^ 1]])
    			return bin[dep] + query(ch[u][t ^ 1],ch[v][t ^ 1],x,dep - 1);
    		return query(ch[u][t],ch[v][t],x,dep - 1);
    	}
    }T;
    int main(){
    	bin[0] = 1; for (int i = 1; i <= Bit; i++) bin[i] = bin[i - 1] << 1;
    	n = read(); m = read(); B = (int)sqrt(n) + 1;
    	n++;
    	for (int i = 2; i <= n; i++) A[i] = read();
    	for (int i = 1; i <= n; i++){
    		sum[i] = sum[i - 1] ^ A[i];
    		T.rt[i] = T.ins(T.rt[i - 1],sum[i]);
    		block[i] = i / B;
    	}
    	for (int i = 1; i <= n; i++){
    		if (i == 1 || block[i] != block[i - 1]){
    			int b = block[i];
    			for (int j = i; j <= n; j++){
    				f[b][j] = max(f[b][j - 1],T.query(T.rt[j - 1],T.rt[i - 1],sum[j],Bit));
    			}
    		}
    	}
    	n--;
    	LL l,r,x,y;
    	while (m--){
    		x = read(); y = read();
    		l = min (((x + lans) % n) + 1, ((y + lans) % n) + 1);
    		r = max (((x + lans) % n) + 1, ((y + lans) % n) + 1) + 1;
    		lans = 0;
    		if (block[l] != block[r]) lans = f[block[l] + 1][r];
    		for (int i = l; block[i] == block[l] && i < r; i++){
    			lans = max(lans,T.query(T.rt[r],T.rt[i],sum[i],Bit));
    		}
    		printf("%lld
    ",lans);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    JavaScript 循环绑定之变量污染
    JavaScript 函数初级
    JavaScript 异常处理
    JavaScript 分支结构
    定位布局
    浮动布局
    css 伪类选择器
    readlink、find-exec参数、file命令
    pwd命令和修改PS1环境变量在bash行的显示
    split、paste命令
  • 原文地址:https://www.cnblogs.com/Mychael/p/8711218.html
Copyright © 2011-2022 走看看