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

    点此看题面

    大致题意: 给定一个序列,每次询问一段区间内最大连续异或和。

    前言

    好吧,看来我总是把可持久化(Trie)树想得太高级了,以为它什么都能搞。。。

    结果做了几道题之后发现可持久化(Trie)树实际上似乎也就只能求一个数与一段区间内数的最大异或和,其他东西还是得另想其他方法去做。(或者还有其他用法只是我太菜不知道)

    就好比这题,我一直在想怎么用纯粹的可持久化(Trie)树去搞,根本没往分块想。等到看到分块的标签之后,才发现其实就是一道智障题。

    分块

    一个显然的想法,如果我们把所有元素做一个前缀异或和,那么问题就变成了求出区间内两个数异或的最大值。

    考虑我们先预处理(ans_{i,j})表示从(i)个块的左端点(j)个位置的答案,显然可以(O(sqrt n))枚举每一个块,然后(O(nlogn))枚举每一个位置用可持久化(Trie)树计算答案。

    对于询问,由于完整块的答案已经预处理好了,我们只要求出左边不完整块的答案,那么(O(sqrt n))枚举不完整块中的每一个元素,然后(O(logn))利用可以持久化(Trie)树询问,就可以了。

    代码

    #pragma GCC optimize(2)
    #pragma GCC optimize("inline")
    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 12000
    #define LN 30
    using namespace std;
    int n,a[N+5];
    class Trie//可持久化Trie树
    {
    	private:
    		#define ST(op) O[x].S[op],O[y].S[op],v,d-1
    		int Nt,Rt[N+5];struct node {int Sz,S[2];}O[(N+1)*(LN+2)+5];
    		I void Ins(int& x,CI y,CI v,CI d)//插入
    		{
    			if(++(O[x=++Nt]=O[y]).Sz,!~d) return;Ins(ST(v>>d&1));
    		}
    		I int Qry(CI x,CI y,CI v,CI d)//询问
    		{
    			if(!~d) return 0;RI t=v>>d&1^1;
    			return O[O[x].S[t]].Sz^O[O[y].S[t]].Sz?Qry(ST(t))|(1<<d):Qry(ST(t^1));
    		}
    	public:
    		I void Ins(CI v,CI x) {Ins(Rt[v],v?Rt[v-1]:0,x,LN);}
    		I int Qry(CI l,CI r,CI x) {return Qry(Rt[l-1],Rt[r],x,LN);}
    }T;
    class Block//分块
    {
    	private:
    		#define SN 150
    		int sz,bl[N+5],ans[SN+5][N+5];
    	public:
    		I void Init()//预处理答案
    		{
    			RI i,j;for(T.Ins(0,0),sz=sqrt(n),i=1;i<=n;++i) bl[i]=(i-1)/sz+1,T.Ins(i,a[i]);
    			for(i=1;i<=bl[n];++i) for(j=(i-1)*sz+2;j<=n;++j)//枚举块以及相应位置
    				ans[i][j]=max(ans[i][j-1],T.Qry((i-1)*sz+1,j-1,a[j]));//累计答案
    		}
    		I int Qry(CI l,CI r)//询问
    		{
    			RI i,t=0;if(bl[l]==bl[r]) {for(i=l;i^r;++i) t=max(t,T.Qry(i+1,r,a[i]));return t;}//如果在一个块中
    			for(i=bl[l]*sz;i>=l;--i) t=max(t,T.Qry(i+1,r,a[i]));return max(t,ans[bl[l]+1][r]);//枚举不完整块的元素计算答案
    		}
    }B;
    int main()
    {
    	RI Qt,i,x,y,lst=0;for(scanf("%d%d",&n,&Qt),i=1;i<=n;++i) scanf("%d",a+i),a[i]^=a[i-1];//做前缀异或和
    	B.Init();W(Qt--) scanf("%d%d",&x,&y),x=(0LL+x+lst)%n+1,
    		y=(0LL+y+lst)%n+1,printf("%d
    ",lst=B.Qry(min(x,y)-1,max(x,y)));
    	return 0;
    }
    
  • 相关阅读:
    《黑马程序员》 内存管理的认识(Objective
    《黑马程序员》 description方法(Objective
    《黑马程序员》 类的加载和初始化(Objective
    《黑马程序员》 category分类的使用(Objective
    《黑马程序员》 OC构造方法(Objective
    《黑马程序员》 OC编译器特性(Objective
    《黑马程序员》 OC的三大特性(Objective
    《黑马程序员》 OC的认识和第一个OC(Objective
    《黑马程序员》 extern与static的使用注意(C语言)
    《黑马程序员》 typedef的使用方法(C语言)
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ2741.html
Copyright © 2011-2022 走看看