[COCI 2023/2024 #2] Dizalo
无删除
先分析 \(q=0\) 这个部分分,以便下文的展开。实际上认真看完题目,我们可以发现处理完一个点后,只要让 \(i\) 前的点按 \(a_i\) 升序排列,就可使答案最小,显然成立,这里不做证明。
很容易发现,若一个数后面存在一个数小于该数,则这个数不会产生任何附加代价。因此需要计算附加代价的数应该是序列的后缀最小值。
至此,我们将问题转换为,求每个后缀最小值 \(a_i\) 之前有多少个数大于 \(a_i\)。同时,注意题目里的条件,\(a\) 数组为一个全排列。又由于 \(a_i\) 为后缀最小值,那么就可以知道,序列一共有 \(n-a_i\) 个数大于当前数,而 \(a_i\) 后面共有 \(n-i\) 个数大于 \(a_i\),则 \(a_i\) 前共有 \(i-a_i\) 个数大于 \(a_i\)。
带删除
对于删除操作,我们需要再引入一个变量,时间戳。此处时间戳记录当前节点被删除的时间,假设我们已经完成了对时间戳的预处理,记为 \(del\) 数组,那么我们接下来要求的,就是当前点 \(i\) 之前有多少个数满足 \(i > j,a_i < a_j,del_i > del_j\),可以尝试使用三维偏序,这里不展开。
接着讨论删除过程,删除操作分为两种,一种是删除一个后缀最小值,另一种是删除一个非后缀最大值,分别进行分析。
-
后缀最小值:当它是一个后缀最小值时,要消除它之前造成的所有影响,一方面我们从事先存下来的后缀最小值集合中删去这个点,同时删去其造成的额外代价,另一方面,我们要在集合中添加上新的后缀最小值。
-
非后缀最小值:当它不是后缀最小值,减去他后面比他小的后缀最小值的数量。
我采用了树状数组进行维护,三个树状数组。
\(bit1\) 维护编号 \(1 \sim i\) 中没被删除的数的个数,
\(bit2\) 维护值 \(1 \sim i\) 中没被删除的数的个数,
\(bit3\) 维护区间后缀最小值个数。
Code
#include<bits/stdc++.h>
#define PII pair<int,int>
#define int long long
#define ls (o<<1)
#define rs (o<<1|1)
#define lowbit(a) ((a)&(-a))
#define mkp make_pair
using namespace std;
const int N=1e5+10;
int n,Q;
int a[N],tim[N],que[N];
bool vis[N],del[N];
vector<int> g[N];
set<PII> st;
int sum;
struct Binary_Tree {
int c[N];
void add(int i,int v) {
for(; i<=n; i+=lowbit(i))c[i]+=v;
}
void build() {
for(int i=1; i<=n; ++i)add(i,1);
}
int query(int i) {
int res=0;
for(; i; i^=lowbit(i))res+=c[i];
return res;
}
} bit1,bit2,bit3;
struct Segment_Tree {
struct node {
int l,r,c;
} tr[N<<2];
void pushup(int o) {
tr[o].c=max(tr[ls].c,tr[rs].c);
}
void build(int o,int l,int r) {
tr[o]= {l,r,0};
if(l==r)return;
int mid=tr[o].l+tr[o].r>>1;
build(ls,l,mid),build(rs,mid+1,r);
}
void update(int o,int i,int x) {
if(tr[o].l==tr[o].r)tr[o].c=x;
else {
int mid=tr[o].l+tr[o].r>>1;
if(mid>=i)update(ls,i,x);
else update(rs,i,x);
pushup(o);
}
}
int query(int o,int l,int r) {
if(l<=tr[o].l&&tr[o].r<=r)return tr[o].c;
int res=0;
int mid=tr[o].l+tr[o].r>>1;
if(mid>=l)res=max(res,query(ls,l,r));
if(mid<r)res=max(res,query(rs,l,r));
return res;
}
} re;
signed main() {
scanf("%lld%lld",&n,&Q);
bit1.build();
bit2.build();
re.build(1,1,n);
for(int i=1; i<=n; ++i)cin>>a[i],tim[i]=Q+1;
for(int i=1; i<=Q; ++i)cin>>que[i],tim[que[i]]=i;
for(int i=n; i>=1; --i)g[re.query(1,1,a[i]-1)].push_back(i),re.update(1,a[i],tim[i]);
st.insert(mkp(0,0));
st.insert(mkp(n+1,n+1));
for(int i:g[0]) {
sum+=i-a[i];
bit3.add(i,1);
vis[i]=1;
st.insert(mkp(a[i],i));
}
printf("%lld ",sum+n);
for(int i=1; i<=Q; ++i) {
del[que[i]]=1;
if(vis[que[i]]) {
bit3.add(que[i],-1);
sum-=bit1.query(que[i])-bit2.query(a[que[i]]);
st.erase(mkp(a[que[i]],que[i]));
} else sum-=bit3.query((--st.lower_bound(mkp(a[que[i]],0)))->second)-bit3.query(que[i]);
bit1.add(que[i],-1);
bit2.add(a[que[i]],-1);
for(int j:g[i]) {
if(del[j])continue;
bit3.add(j,1);
vis[j]=1;
st.insert(mkp(a[j],j));
sum+=bit1.query(j)-bit2.query(a[j]);
}
printf("%lld ",sum+n-i);
}
return 0;
}

浙公网安备 33010602011771号