BZOJ3166 [Heoi2013]Alo 可持久化Trie

来源:互联网 发布:易金通软件客服电话 编辑:程序博客网 时间:2024/05/24 04:45

题意:给定长度为n的整数序列,一个连续子段的收益为子段次大值xor子段中任意数,求最大收益子段值

Sol:

考虑枚举次大值是谁,则一个数作为次大值时的扩张范围是[左边第二个大于她的数+1 , 右边第一个大于她的数-1] 和 [左边第一个大于她的数+1 , 右边第二个大于她的数-1] 

两个区间可以合并起来,用可持久化Trie查询最大异或值。

找左右数可以将所有数从小到大排序后顺序枚举,每次插入到set里查询

也可以用双向链表维护,每次删除即可

Code:

#include<bits/stdc++.h>#define debug(x) cout<<#x<<"="<<x<<endlusing namespace std;const int maxn = 50009;const int Log = 30;const int inf = 0x3f3f3f3f; int n,mx,ans;int pre[maxn],nxt[maxn],rt[maxn];struct Trie{    int son[maxn*Log*2][2],cnt[maxn*Log*2];    int tot;    inline int insert(int x,int num)    {        int tmp,y;tmp=y=++tot;        for(int i=Log;i>=0;i--)        {            son[y][0]=son[x][0];son[y][1]=son[x][1];            cnt[y]=cnt[x]+1;            int wh=(num>>i)&1;            son[y][wh]=++tot;            x=son[x][wh];y=son[y][wh];        }cnt[y]=cnt[x]+1;        return tmp;    }    inline int query(int l,int r,int num)    {        int res=0;        for(int i=Log;i>=0;i--)        {            int wh=(num>>i)&1;            if(cnt[son[r][wh^1]]-cnt[son[l][wh^1]]) res|=(1<<i),r=son[r][wh^1],l=son[l][wh^1];            else r=son[r][wh],l=son[l][wh];        }        return res;    }}uuz;struct node{int pos,val;}a[maxn]; inline int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}inline bool cmp(const node &x,const node &y){    return x.val<y.val;} int main(){    n=read();    for(int i=1;i<=n;i++)    {        a[i]=(node){i,read()};        rt[i]=uuz.insert(rt[i-1],a[i].val);    }    for(int i=1;i<=n;i++) pre[i]=i-1,nxt[i]=i+1;    pre[0]=0;nxt[n+1]=n+1;nxt[0]=1;pre[n+1]=n;    sort(a+1,a+1+n,cmp);    for(int i=1;i<=n;i++)    {        int now=a[i].pos;        int L=pre[now],R=nxt[now];        int l=pre[L],r=nxt[R];        if(l+1<=R-1) ans=max(ans,uuz.query(rt[l],rt[R-1],a[i].val));        if(L+1<=r-1) ans=max(ans,uuz.query(rt[L],rt[r-1],a[i].val));        nxt[pre[now]]=nxt[now];        pre[nxt[now]]=pre[now];    }    cout<<ans;    return 0;}


原创粉丝点击