bzoj3166: [Heoi2013]Alo

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3166

题意:中文题。

分析:枚举每个元素,将它当成那个次大值,然后在它所作用的区间内找异或最大值即可。怎么找它作用的区间呢?用set和priority_queue一起,用优先队列使得大的元素的位置先进set。然后对于每一个新位置找他前面和后面的位置边界即可。我写得好丑~O(nlog(max(a[i])))

代码:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=50100;
const int MAX=1000000100;
const int mod=100000000;
const int MOD1=1000000007;
const int MOD2=1000000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=998244353;
const ll INF=10000000010;
typedef double db;
typedef unsigned long long ull;
set<int>Q;
priority_queue<pair<int,int> >P;
int e[35],a[N],l[N],r[N];
int siz,root[N],tr[35*N][2],sum[35*N];
int add(int x,int z) {
    int i,t,y,ret=siz+1;
    y=++siz;sum[y]=sum[x]+1;
    for (i=31;i>=0;i--) {
        t=(z&e[i])>>i;
        tr[y][0]=tr[x][0];tr[y][1]=tr[x][1];
        tr[y][t]=++siz;y=tr[y][t];
        x=tr[x][t];sum[y]=sum[x]+1;
    }
    return ret;
}
int query(int x,int y,int z) {
    int i,t,ret=0;
    for (i=31;i>=0;i--) {
        t=(z&e[i])>>i;
        if (sum[tr[y][t^1]]>sum[tr[x][t^1]]) {
            ret+=e[i];x=tr[x][t^1];y=tr[y][t^1];
        } else { x=tr[x][t];y=tr[y][t]; }
    }
    return ret;
}
int main()
{
    int i,n,ans=0;
    scanf("%d", &n);
    e[0]=1;for (i=1;i<35;i++) e[i]=2*e[i-1];
    for (i=1;i<=n;i++) {
        scanf("%d", &a[i]);P.push(make_pair(a[i],i));
    }
    for (i=1;i<=n;i++) root[i]=add(root[i-1],a[i]);
    pair<int,int>kk;
    set<int>::iterator it,is;
    while (!P.empty()) {
        kk=P.top();P.pop();
        Q.insert(kk.second);
        it=is=Q.find(kk.second);
        if (is!=Q.begin()) {
            is--;
            if (is!=Q.begin()) {
                is--;l[kk.second]=*is;
            } else l[kk.second]=0;
        } else l[kk.second]=0;
        is=it;is++;
        if (is!=Q.end()) {
            is++;
            if (is!=Q.end()) {
                r[kk.second]=*is;
            } else r[kk.second]=n+1;
        } else r[kk.second]=n+1;
    }
    for (i=1;i<=n;i++) ans=max(ans,query(root[l[i]],root[r[i]-1],a[i]));
    printf("%d\n", ans);
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值