#loj3094 [BJOI2019]删数
作者:互联网
不妨换个想法,构造出一个可以被删光的数列,最大化这个数列和原来数列相同的元素个数
显然一个可以被删光的数列可以分成几段相同的数字,并且每段数字的值刚好等于小于等于这种数字的元素个数
那么可以想出一个naive的dp做法,去dp这些段,
转移方程为
\[dp(i)=max(dp(j)+min(i-j,cnt(i)))\]
这个方程是有组合意义的,数轴上有若干个形如\((i-cnt(i)+1,i)\)的区间
那么\(dp(i)\)代表的就是\((1,i)\)这段区间中线段的并长度
既然是线段求并显然可以转化为区间加然后数0的个数
线段树维护区间最小值及其个数即可了
而操作2相当于更改询问的区间,这个也很简单
注意一件事情,如果一个线段的开头不在询问区间当中,这个线段会被完全删除
在询问区间左移或者右移的时候记得删除这些线段就行了
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;const int N=7*1e5+10;typedef long long ll;
map <int,int> mp;
struct linetree
{
int mi[N<<2];int micnt[N<<2];int add[N<<2];
inline void pd(int p,int p1,int p2)
{
if(add[p])
mi[p1]+=add[p],mi[p2]+=add[p],
add[p1]+=add[p],add[p2]+=add[p],add[p]=0;
}
inline void mg(int p,int p1,int p2)
{
if(mi[p1]==mi[p2])
mi[p]=mi[p1],micnt[p]=micnt[p1]+micnt[p2];
else if(mi[p1]<mi[p2])
mi[p]=mi[p1],micnt[p]=micnt[p1];
else
mi[p]=mi[p2],micnt[p]=micnt[p2];
}
inline void build(int p,int l,int r)
{
// printf("build %d %d %d\n",p,l,r);
if(r-l==1){mi[p]=mp[r],micnt[p]=1;return;}
int mid=(l+r)/2;
build(p<<1,l,mid);build(p<<1|1,mid,r);
mg(p,p<<1,p<<1|1);
}
inline void stadd(int p,int l,int r,int dl,int dr,int pl)
{
if(dl==l&&dr==r)
{
add[p]+=pl;mi[p]+=pl;return;
}int mid=(l+r)/2;
pd(p,p<<1,p<<1|1);
if(dl<mid)stadd(p<<1,l,mid,dl,min(dr,mid),pl);
if(mid<dr)stadd(p<<1|1,mid,r,max(dl,mid),dr,pl);
mg(p,p<<1,p<<1|1);
}
inline void qry(int p,int l,int r,int dl,int dr)
{
if(dl==l&&dr==r){mg(0,0,p);return;}
int mid=(l+r)/2;
pd(p,p<<1,p<<1|1);
if(dl<mid)qry(p<<1,l,mid,dl,min(dr,mid));
if(mid<dr)qry(p<<1|1,mid,r,max(dl,mid),dr);
}
inline int cqry(int l,int r,int dl,int dr)
{
// printf("cqry %d %d %d %d\n",l,r,dl,dr);
mi[0]=0x3f3f3f3f;micnt[0]=0;
qry(1,l,r,dl,dr);return micnt[0]*(mi[0]==0);
}
}lt;int RGL;int RGR;int we[N];int QL;int QR;
map <int,int> cnt;int n;int m;int add;
inline void inc(int val)
{
int pos=val-(++cnt[val])+1;
if(val<=QR)
{
//printf("inc %d\n",val);
lt.stadd(1,RGL,RGR,pos-1,pos,1);
}
}
inline void dec(int val)
{
int pos=val-(cnt[val]--)+1;
// printf("dec %d,pos=%d",val,pos);
if(val<=QR)
{
//printf("dec %d\n",val);
lt.stadd(1,RGL,RGR,pos-1,pos,-1);
}
}
inline void ins(int val)
{
// printf("ins %d %d\n",val-cnt[val],val);
if(cnt[val])lt.stadd(1,RGL,RGR,val-cnt[val],val,1);
}
inline void del(int val)
{
// printf("del %d %d\n",val-cnt[val],val);
if(cnt[val])lt.stadd(1,RGL,RGR,val-cnt[val],val,-1);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&we[i]);
for(int i=1;i<=n;i++)cnt[we[i]]++;
for(map <int,int> :: iterator it=cnt.begin();it!=cnt.end();++it)
for(int j=it->first,k=1;k<=it->second;j--,k++)mp[j]++;
RGL=-n-m;RGR=n+m;
QL=0;QR=n;
lt.build(1,RGL,RGR);
for(int i=1,p;i<=m;i++)
{
scanf("%d",&p);
if(p>0)
dec(we[p]),scanf("%d",&we[p]),we[p]-=add,inc(we[p]);
else
{
scanf("%d",&p);add+=p;
if(p==-1)
QR++,QL++,ins(QR);
else
del(QR),QR--,QL--;
}
// printf("qry %d %d\n",QL,QR);
printf("%d\n",lt.cqry(RGL,RGR,QL,QR));
}return 0;
}
标签:BJOI2019,cnt,QR,int,线段,删数,++,loj3094,dp 来源: https://www.cnblogs.com/sweetphoenix/p/10815098.html