题解:P9596 [JOI Open 2018] 冒泡排序 2
liuhangxin · · 题解
P9596 [JOI Open 2018] 冒泡排序 2
一个序列
证明:
发现一次操作必定将恰好一个
发现同样的值只有最后一个位置
开棵权值线段树直接维护这个式子的最值,用 set 维护每种颜色的位置集合即可。
代码如下:
#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define fi first
#define se second
using namespace std;
const int N=1e6+10,inf=1e9;
int n,q;
int a[N],stk[N],cnt;
int p[N],v[N];
set<int>s[N];
int Max[4*N],tag[4*N];
#define mid (l+r)/2
#define L 2*u
#define R 2*u+1
void change(int u,int l,int r,int lp,int rp,int v)
{
if(lp>rp)return;
if(lp<=l&&r<=rp)
{
Max[u]+=v;
tag[u]+=v;
return;
}
if(lp<=mid)change(L,l,mid,lp,rp,v);
if(rp>mid)change(R,mid+1,r,lp,rp,v);
Max[u]=max(Max[L],Max[R])+tag[u];
}
void Add(int c,int p){
change(1,1,cnt,1,c-1,1);
if(!s[c].size())change(1,1,cnt,c,c,inf-n);
else change(1,1,cnt,c,c,-*prev(s[c].end()));
s[c].insert(p);
change(1,1,cnt,c,c,*prev(s[c].end()));
}
void Del(int c,int p)
{
change(1,1,cnt,1,c-1,-1);
change(1,1,cnt,c,c,-*prev(s[c].end()));
s[c].erase(p);
if(!s[c].size())change(1,1,cnt,c,c,-(inf-n));
else change(1,1,cnt,c,c,*prev(s[c].end()));
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),stk[++cnt]=a[i];
for(int i=1;i<=q;i++)
{
scanf("%d%d",&p[i],&v[i]);p[i]++;
stk[++cnt]=v[i];
}
sort(stk+1,stk+cnt+1);
cnt=unique(stk+1,stk+cnt+1)-stk-1;
for(int i=1;i<=cnt;i++)change(1,1,cnt,i,i,-inf);
for(int i=1;i<=n;i++)a[i]=lower_bound(stk+1,stk+cnt+1,a[i])-stk;
for(int i=1;i<=q;i++)v[i]=lower_bound(stk+1,stk+cnt+1,v[i])-stk;
for(int i=1;i<=n;i++)
Add(a[i],i);
for(int i=1;i<=q;i++)
{
Del(a[p[i]],p[i]);
a[p[i]]=v[i];
Add(a[p[i]],p[i]);
printf("%d\n",Max[1]);
}
return 0;
}