bzoj 2741 分块 + 可持久化trie


题意是求  【a,b】 中 的最大字段异或和。 。

看了神牛题解才会的。

首先将 区间  转化成   前项和 中两个的异或值。 

也就是 将 1- n 个数a[ ],转化成 0-n 个数的数列b[ ]。 

也就是

b[ r ] ^ a[ l ]  = a[l+1] ^ a[l+2]^...^a[ r ]

b[2] ^ b[ 0 ] = a[1 ]^a[ 2 ]

在查询 【l,r】 转化成 b【】上的 【l-1, r】上的查询。(没处理好 ,一直在b【】 上 查询【l,r】 ,wa 成狗了。。)


于是此题问  就转化成了 在  在区间查询 两个点最大异或值。


对于一个点,查询是 【l,r】 是 复杂度 是 O(nlgm)  : m 是 数列中最大值  lgm 是其位数。

所以求区间 任取两个点的最大异或值 ,lgn 应该没有解法。

于是参考神牛的解法, 分块,维护每一块的块头那个点 和其后边的每一个点 代表的区间中的最大值,

每一块块头部点 共有sqrt(n) 个,

f[ i ][j] = max(f[i][j-1],query(idx[i],j)); 第i块到 j的位置的最大值。

预处理的复杂度 O(nsqrt(n)*lgm)

查询时 暴力 第一块。 第二块的开头到 r 已经预处理出来了。


#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <cstring>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <assert.h>
#include <queue>
#define REP(i,n) for(int i=0;i<n;i++)
#define TR(i,x) for(typeof(x.begin()) i=x.begin();i!=x.end();i++)
#define ALLL(x) x.begin(),x.end()
#define SORT(x) sort(ALLL(x))
#define CLEAR(x) memset(x,0,sizeof(x))
#define FILLL(x,c) memset(x,c,sizeof(x))
using namespace std;
const double eps = 1e-9;
#define LL long long
#define pb push_back
const int maxn  = 31000;
const int T = 130;
int dp[100][maxn];
int a[maxn];
int b[maxn];
struct Node{
   Node *s[2];
   int sum;
}nodes[maxn*300];
Node *root[maxn],*null;
int C;
int n,m;

void init(){
    C=0;
    root[0] = null = &nodes[C++];
    null->s[0] = null->s[1] = null;
    null->sum = 0;
}
Node *insert(int v,int d,Node *root){
     Node *rt = &nodes[C++];
     rt->s[0] = root->s[0];
     rt->s[1] = root->s[1];
     rt->sum = root->sum+1;
     if(d<0)return rt;
     int p = (v>>d)&1;
     rt->s[p] = insert(v,d-1,root->s[p]);
     return rt;
}
int query(int v,int d,Node *rt1,Node *rt2){
    if(d<0)return 0;
    int p = (v>>d)&1;
    if(rt2->s[p^1]->sum - rt1->s[p^1]->sum){
          return (1<<d)+query(v,d-1,rt1->s[p^1],rt2->s[p^1]);
    }
    return query(v,d-1,rt1->s[p],rt2->s[p]);
}
const int K = 31;
void solve(){
	init();
	CLEAR(dp);
	for(int i=0;i<=n;i++){
		root[i+1] = insert(b[i],K,root[i]);
	}
}
int get_ans(int l,int r){
	 int ans = 0;
     l--;
	 int l_id = l/T+1;
	 int r_id = r/T+1;
     if(r_id > l_id){
     	ans = dp[l_id+1][r];
     }
     for(int i=l;i<=min(r,(l_id+1)*T);i++){
     	ans = max(ans,query(b[i],K,root[l],root[r+1]));
     }
	 return ans;
}
void solve1(){
	int lastans = 0 ;
	for(int i=1;i<=m;i++){
		 int l,r,x,y;
		 scanf("%d%d",&x,&y);
		 l = min(((x+lastans%n)%n)+1,((y+lastans%n)%n)+1);
         r = max(((x+lastans%n)%n)+1,((y+lastans%n)%n)+1);
         int ans = get_ans(l,r);
         printf("%d\n",ans);
         lastans = ans;
	}
	
}
int main(){
    scanf("%d%d",&n,&m);
    CLEAR(b);
    for(int i=1;i<=n;i++){
    	 scanf("%d",&a[i]);
    	 b[i] = b[i-1]^a[i];
    }
    solve();
    for(int i=1;i<=n;i++){
    	 int idx = i/T+1;
    	 for(int j=1;j<=idx;j++){
    	       int l_idx =(j-1)*T;
    	       dp[j][i] = max(dp[j][i-1],query(b[i],K,root[l_idx],root[i+1]));
    	 }
    }
    solve1();
    return 0;
}



你可能感兴趣的:(bzoj 2741 分块 + 可持久化trie)