3166: [Heoi2013]Alo

题意:

找到一个区间,设 k k k位区间次大值,求 m a x ( k ⊕ a [ i ] ∣ l ≤ i ≤ r ) max(k \oplus a[i]|l\le i \le r) max(ka[i]lir)

题解:

首先考虑某个值为次大值的区间,有且仅有一个值比他大,这个可以排序+set求出。
然后求区间与一个值的异或最大值就是可持久化trie经典题了。
code:

#include<set>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n;
struct node{int a,num;}a[50010];
bool cmp(node a,node b) {return a.a>b.a;}
struct trnode{int lc,rc,c;}tr[3000010];int tot=0,root[50010];
void change(int &x,int k,int d)
{
    tr[++tot]=tr[x];x=tot;
    if(k==-1) {tr[x].c++;return;}
    int c=(d&(1<<k))?1:0;
    if(!c) change(tr[x].lc,k-1,d);
    else change(tr[x].rc,k-1,d);
    tr[x].c=tr[tr[x].lc].c+tr[tr[x].rc].c;
}
set<int> s;
int ans=0;
void solve(int d,int l,int r)
{
    //printf("%d %d %d\n",d,l,r);
    int s=0;
    int x1=root[l-1],x2=root[r];
    for(int i=30;i>=0;i--)
    {
        s<<=1;
        int c=((1<<i)&d)?1:0;
        int lcc=tr[tr[x2].lc].c-tr[tr[x1].lc].c;
        int rcc=tr[tr[x2].rc].c-tr[tr[x1].rc].c;
        //printf("c:%d %d\n",c,rcc);
        //if(s) printf("put:%d %d %d\n",i,lcc,rcc);
        if(c)
        {
            if(lcc) x1=tr[x1].lc,x2=tr[x2].lc;
            else x1=tr[x1].rc,x2=tr[x2].rc,s++;
        }
        else
        {
            if(rcc) x1=tr[x1].rc,x2=tr[x2].rc,s++;
            else x1=tr[x1].lc,x2=tr[x2].lc;
        }
    }
    //printf("s:%d\n",s);
    ans=max(ans,s^d);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i].a);a[i].num=i;
        root[i]=root[i-1];
        change(root[i],30,a[i].a);
    }
    sort(a+1,a+n+1,cmp);
    s.insert(0);s.insert(n+1);
    s.insert(a[1].num);
    for(int i=2;i<=n;i++)
    {
        //printf("a:%d %d\n",a[i].a,a[i].num);
        int l=*(--s.lower_bound(a[i].num)),r=*s.lower_bound(a[i].num);
        //printf("l r:%d %d\n",l,r);
        if(l!=0) solve(a[i].a,*(--(--s.lower_bound(a[i].num)))+1,r-1);
        if(r!=n+1) solve(a[i].a,l+1,(*(++s.upper_bound(a[i].num)))-1);
        s.insert(a[i].num);
    }
    printf("%d",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值