卡牌游戏

题目描述

这里写图片描述

线段树

枚举改变规则分界线,然后根据贪心,对前后部分进行计算,假如分界线前有j张牌,那么我们一定拿最大j张牌去搞事情。
用权值线段树维护一个区间,我们用一些牌去打赢对方的牌后,我们剩多少牌无法打败对方任何一张牌,对方剩多少牌无法被打败。
合并就很容易了,比如现在是大者胜,我们剩的牌数=左区间我们剩的牌数+max(右区间我们剩的牌数-左区间对方剩的牌数,0)
最后只要知道我们剩了多少张牌,就知道我们赢了多少局。

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=50000+10;
struct dong{
    int a,b;
} tree[maxn*8],tree2[maxn*8];
int a[maxn],b[maxn];//c <- sort d -> sort
bool bz[maxn*2];
int i,j,k,l,t,n,m,ans,top,tot;
void insert(int p,int l,int r,int wz,int v){
    if (l==r){
        if (v==1) tree[p].b++;
        else tree[p].a++;
        return;
    }
    int mid=(l+r)/2;
    if (wz<=mid) insert(p*2,l,mid,wz,v);
    else insert(p*2+1,mid+1,r,wz,v);
    tree[p].a=tree[p*2+1].a+max(tree[p*2].a-tree[p*2+1].b,0);
    tree[p].b=tree[p*2].b+max(tree[p*2+1].b-tree[p*2].a,0);
}
void insert2(int p,int l,int r,int wz,int v){
    if (l==r){
        if (v==1) tree2[p].b++;
        else tree2[p].a++;
        return;
    }
    int mid=(l+r)/2;
    if (wz<=mid) insert2(p*2,l,mid,wz,v);
    else insert2(p*2+1,mid+1,r,wz,v);
    tree2[p].a=tree2[p*2].a+max(tree2[p*2+1].a-tree2[p*2].b,0);
    tree2[p].b=tree2[p*2+1].b+max(tree2[p*2].b-tree2[p*2+1].a,0);
}
void del(int p,int l,int r,int wz,int v){
    if (l==r){
        if (v==1) tree2[p].b--;
        else tree2[p].a--;
        return;
    }
    int mid=(l+r)/2;
    if (wz<=mid) del(p*2,l,mid,wz,v);
    else del(p*2+1,mid+1,r,wz,v);
    tree2[p].a=tree2[p*2].a+max(tree2[p*2+1].a-tree2[p*2].b,0);
    tree2[p].b=tree2[p*2+1].b+max(tree2[p*2].b-tree2[p*2+1].a,0);
}
int main(){
    scanf("%d",&n);
    fo(i,1,n) scanf("%d",&a[i]),bz[a[i]]=1;
    t=0;
    fo(i,1,2*n) 
        if (!bz[i]) b[++t]=i;
    fo(i,1,n){
        insert2(1,1,2*n,b[i],1);
        insert2(1,1,2*n,a[i],-1);
    }
    fo(i,1,n+1){
        ans=max(ans,n-tree[1].a-tree2[1].a);
        if (i>n) break;
        insert(1,1,2*n,b[n-i+1],1);
        insert(1,1,2*n,a[i],-1);
        del(1,1,2*n,b[n-i+1],1);
        del(1,1,2*n,a[i],-1);
    }
    printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值