BZOJ3166: [Heoi2013]Alo

41 篇文章 0 订阅
2 篇文章 0 订阅

每个宝石找出他能产生贡献即他是最大值的区间,【左边的第二个比他大的+1~右边的第二个比他大的-1】
然后写个可持久化trie每个宝石算一下最大值就好了
找左右第二个比他大的可以按宝石的权值从大到小插入,在线段树上二分


code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e9
using namespace std;

void up(int &x,int y){if(x<y)x=y;}
void down(int &x,int y){if(x>y)x=y;}

const int maxn = 51000;
struct node
{
    int c,i;
}s[maxn];
bool cmp(node x,node y){return x.c>y.c;}
int n,a[maxn],le[maxn],ri[maxn];
int tr[maxn<<3];

void ins(int x,int l,int r,int loc)
{
    if(l==r) {tr[x]=1; return ;}
    int mid=(l+r)>>1,lc=x<<1,rc=lc|1;
    if(loc<=mid) ins(lc,l,mid,loc);
    else ins(rc,mid+1,r,loc);
    tr[x]++;
}
int q1(int x,int l,int r,int loc,int &k)
{
    if(l==r) { k--; return l; }
    int mid=(l+r)>>1,lc=x<<1,rc=lc|1;
    if(loc<=mid&&loc>=l) return q1(lc,l,mid,loc,k);
    else
    {
        int re;
        if(tr[rc]) re=q1(rc,mid+1,r,loc,k);
        if(!k) return re;
        else
        {
            if(tr[lc]>=k) return q1(lc,l,mid,loc,k);
            else {k-=tr[lc]; return re;}
        }
    }
}
int q2(int x,int l,int r,int loc,int &k)
{
    if(l==r) { k--; return l; }
    int mid=(l+r)>>1,lc=x<<1,rc=lc|1;
    if(loc>mid&&loc<=r) return q2(rc,mid+1,r,loc,k);
    else
    {
        int re;
        if(tr[lc]) re=q2(lc,l,mid,loc,k);
        if(!k) return re;
        else
        {
            if(tr[rc]>=k) return q2(rc,mid+1,r,loc,k);
            else {k-=tr[rc]; return re;}
        }
    }
}
struct trie
{
    int lc,rc,c;
}te[maxn*80]; int num;
int bit[34];
int root[maxn];
void newte(int &x)
{
    x=++num;
    te[x].lc=te[x].rc=te[x].c=0;
}
void upd(int &x,int now,int loc)
{
    if(!x) newte(x);
    te[x].c++;
    if(now==31) return ;
    if(loc&bit[now]) upd(te[x].rc,now+1,loc);
    else upd(te[x].lc,now+1,loc);
}
void merge(int &x,int la)
{
    if(!x) { x=la; return ; }
    if(!la) return ;
    te[x].c+=te[la].c;
    merge(te[x].lc,te[la].lc);
    merge(te[x].rc,te[la].rc);
}
int query(trie x1,trie x2,int k,int now,int r)
{
    if(now==31) return r;
    if(k&bit[now])
    {
        if(te[x2.lc].c-te[x1.lc].c) {r|=bit[now]; return query(te[x1.lc],te[x2.lc],k,now+1,r); }
        else return query(te[x1.rc],te[x2.rc],k,now+1,r);
    }
    else
    {
        if(te[x2.rc].c-te[x1.rc].c) {r|=bit[now]; return query(te[x1.rc],te[x2.rc],k,now+1,r); }
        else return query(te[x1.lc],te[x2.lc],k,now+1,r);
    }
}

int main()
{
    num=0; te[0].lc=te[0].rc=te[0].c=0;
    for(int i=0;i<=30;i++) bit[i]=1<<30-i;

    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        s[i].i=i; s[i].c=a[i];
    }
    sort(s+1,s+n+1,cmp);

    for(int i=1;i<=n;i++)
    {
        ins(1,1,n,s[i].i);
        int ki=3;
        le[s[i].i]=q1(1,1,n,s[i].i,ki);
        ki=3;
        ri[s[i].i]=q2(1,1,n,s[i].i,ki);
    }

    for(int i=1;i<=n;i++)
    {
        upd(root[i],0,a[i]);
        merge(root[i],root[i-1]);
    }
    int ret=0;
    for(int i=1;i<=n;i++)
    {
        int l,r;
        l=le[i]+1,r=ri[i]-1;
        if(le[i]==i) l=1;
        if(ri[i]==i) r=n;
        if(i==s[1].i) continue;
        up(ret,query(te[root[l-1]],te[root[r]],a[i],0,0));
    }
    printf("%d\n",ret);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值