zoukankan      html  css  js  c++  java
  • 【BZOJ3166】[HEOI2013] Alo(可持久化Trie树)

    点此看题面

    大致题意:(n)个互不相同的数,对于一段区间,定义其中次大值与区间中另一数异或的最大值为区间的价值。求最大的区间价值。

    枚举次大值

    考虑我们枚举次大值,那么要满足它是次大值,显然要满足区间中有且仅有一个数比它大。

    于是我们在两边分别找到第二个比它大的数的位置(l,r),那么它就可以与([l+1,r-1])这一区域内任一数计算答案。(虽然这一区间左右两边各有一个比它大的数,但我们完全可以在选区间时保证恰有一个)

    而如何求一个数与一段区间内的数的最大异或值,显然可持久化(Trie)啊。

    怎么找到第二个比它大的数

    一开始(naive)了结果就(WA)了一发。。。

    其实我们可以从大到小枚举次大值,同时用(set)维护已经处理过的元素,然后只要找到前驱的前驱/后继的后继,就可以找到第二个比它大的数了。

    具体实现可以详见代码。

    代码

    #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 50000
    #define LV 30
    using namespace std;
    int n,a[N+5],s[N+5];set<int> S;
    class Trie//可持久化Trie
    {
    	private:
    		int Nt,Rt[N+5];struct node {int Sz,S[2];}O[N*(LV+2)+5];
    		I void Ins(int& x,CI y,CI v,CI d)//插入
    		{
    			++(O[x=++Nt]=O[y]).Sz;if(!~d) return;
    			RI t=(v>>d)&1;Ins(O[x].S[t],O[y].S[t],v,d-1);
    		}
    		I int Qry(CI x,CI y,CI v,CI d)//询问
    		{
    			if(!~d) return 0;RI t=(v>>d)&1^1;
    			if(O[O[x].S[t]].Sz^O[O[y].S[t]].Sz) return Qry(O[x].S[t],O[y].S[t],v,d-1)|(1<<d);
    			return Qry(O[x].S[t^1],O[y].S[t^1],v,d-1);
    		}
    	public:
    		I void Ins(CI v,CI x) {Ins(Rt[v],Rt[v-1],x,LV);}
    		I int Qry(CI l,CI r,CI x) {return Qry(Rt[l-1],Rt[r],x,LV);}
    }P;
    I bool cmp(CI x,CI y) {return a[x]<a[y];}
    int main()
    {
    	RI i,T;for(scanf("%d",&n),i=1;i<=n;++i) scanf("%d",a+i),P.Ins(s[i]=i,a[i]);
    	S.insert(-1),S.insert(0),S.insert(n+1),S.insert(n+2);//先插入几个元素防越界
    	RI l,r,t,ans=0;for(sort(s+1,s+n+1,cmp),i=n;i;--i)//从大到小枚举
    		l=*--(--S.lower_bound(s[i])),r=*++S.upper_bound(s[i]),S.insert(s[i]),//找前驱的前驱和后继的后继
    		i^n&&(t=P.Qry(max(l+1,1),min(r-1,n),a[s[i]]),t>ans&&(ans=t));//在对应区间内找答案
    	return printf("%d",ans),0;
    }
    
  • 相关阅读:
    520了,用32做个简单的小程序
    sql使用手册
    大厂Redis高并发场景设计,面试问的都在这!
    如何根据普通ip地址获取当前地理位置
    理解Python闭包,这应该是最好的例子
    520了,用32做个简单的小程序
    适合 C++ 新手学习的开源项目——在 GitHub 学编程
    寄存器(内存访问)01 零基础入门学习汇编语言13
    寄存器(CPU工作原理)07 零基础入门学习汇编语言12
    数组08 零基础入门学习C语言30
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ3166.html
Copyright © 2011-2022 走看看