题目描述
线段树
枚举改变规则分界线,然后根据贪心,对前后部分进行计算,假如分界线前有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);
}