题解:P14676 [ICPC 2025 Seoul R] Mex Culpa
Solution
首先转化 \(a_i\le a_j+b_j,a_j\le a_i+b_i\) 的条件。因为 \(a_i< a_i+b_i\),所以对每个 \(i\) 可将 \(a_i,b_i\) 两个元素转化为区间 \(S_i=[a_i,a_i+b_i]\),那么满足上述条件的 \(j\) 只需满足区间 \(S_j\) 与区间 \(S_i\) 有交集。
如果我们以 \(i\) 从小到大处理,则需维护一个区间赋值、区间 \(\mathtt{mex}\) 的数据结构,然而这是很困难的。考虑到 \(\mathtt{mex}\) 的性质,我们不妨以 \(f_i\) 从小到大处理。
对于所有 \(f_i=0\),就是不存在满足 \(j<i\) 的区间 \(S_j\) 与 \(S_i\) 有交,那么只需找到最小的编号,此时为 \(1\),则 \(f_1=0\),然后将区间 \(S_1\) 染色,找到未被染色的区间中的最小编号 \(i\),则 \(f_i=0\),并重复这一染色过程直至没有未被染色的区间,我们就找到所有 \(f_i=0\) 了。
但是维护未被染色的区间也很困难,那有没有办法不染色呢?发现所有 \(f_i=0\) 的区间 \(S_i\) 是相互无交集的,那么处理完 \(1\) 后直接对 \(S_1\) 左右两边分治,找到当前区间中的最小编号,然后继续分治就好了。其中,找 \(S_i\subset [L,R]\) 区间中的最小编号,就是找满足 \(a_i\ge L,a_i+b_i\le R\) 的最小编号,放到二维平面上用树套树维护最小值即可。
接着对于 \(f_i=1\),不难发现就是把所有 \(f_i=0\) 的区间删除后不存在满足 \(j<i\) 的区间 \(S_j\) 与 \(S_i\) 有交,重复刚刚对 \(f_i=0\) 的操作即可。所以,找到所有 \(f_i=k\) 后,将这些区间在树套树维护的平面上对应的点删除,就能像处理 \(f_i=0\) 一样处理 \(f_i=k+1\) 了。
细节处理方面,由于存在端点相同的区间,即二维平面上横坐标或纵坐标相同的点,在维护最值的树套树上直接进行删除操作可能会出错。那么我们在离散化时把相同的端点给拆成不同的端点处理即可。
时空复杂度 \(\mathcal O(n\log^2 n)\)。
Code
用了树状数组套线段树来实现
#include<bits/stdc++.h>
using namespace std;
namespace io{(快读)}using namespace io;
const int N=2.5e5+5,M=N*2;
int n,m,a[N],b[N],nc,c[M],f[N];
int tot,rt[M],mx[M*100],ls[M*100],rs[M*100];
void pushup(int u){mx[u]=max(mx[ls[u]],mx[rs[u]]);}
void T_upd(int y,int k,int&u,int l=1,int r=m){
if(!u)u=++tot;
if(l==r)return void(mx[u]=k);
int mid=(l+r)/2;
if(y<=mid)T_upd(y,k,ls[u],l,mid);
else T_upd(y,k,rs[u],mid+1,r);
pushup(u);
}
void BIT_upd(int x,int y,int k){x=m+1-x;for(;x<=m;x+=x&-x)T_upd(y,k,rt[x]);}
int T_ask(int p,int q,int u,int l=1,int r=m){
if(!u)return 0;
if(p<=l&&r<=q)return mx[u];
int mid=(l+r)/2,res=0;
if(p<=mid)res=max(res,T_ask(p,q,ls[u],l,mid));
if(q>mid)res=max(res,T_ask(p,q,rs[u],mid+1,r));
return res;
}
int BIT_ask(int l,int r){
int x=m+1-l,y=r,res=0;
for(;x;x-=x&-x)res=max(res,T_ask(1,y,rt[x]));
return res;
}
int now,cnt,cur,mb,nxt[N],L[M],R[M],bel[M];
map<pair<int,int>,int>mp;
vector<int>V,ca[M],cb[M];
void solve(int l=1,int r=m){
if(l>r)return;
int id=BIT_ask(l,r);
if(!id)return;
id=n+1-id;
f[id]=now;cnt++;
V.push_back(id);
solve(l,L[bel[a[id]]]-1);
solve(R[bel[b[id]]]+1,r);
}
int main(){
read(n);
for(int i=1;i<=n;i++)read(a[i]),c[i]=a[i];
for(int i=1;i<=n;i++)read(b[i]),c[n+i]=b[i]+=a[i];
sort(c+1,c+2*n+1);
nc=unique(c+1,c+2*n+1)-c-1;
for(int i=1;i<=n;i++){
a[i]=lower_bound(c+1,c+nc+1,a[i])-c;
b[i]=lower_bound(c+1,c+nc+1,b[i])-c;
ca[a[i]].push_back(i);//记录相同的端点
cb[b[i]].push_back(i);
mb=max(mb,b[i]);
}memset(L,0x3f,sizeof(L));
for(int i=1;i<=mb;i++){//拆成不同的端点
for(int j:ca[i]){
a[j]=++cur;
bel[cur]=i;
L[i]=min(L[i],cur);
R[i]=max(R[i],cur);
}for(int j:cb[i]){
b[j]=++cur;
bel[cur]=i;
L[i]=min(L[i],cur);
R[i]=max(R[i],cur);
}m=max(m,cur);
}
for(int i=1;i<=n;i++)BIT_upd(a[i],b[i],n+1-i);
for(;now<n;now++){
solve();
if(cnt>=n)break;
for(int i:V)BIT_upd(a[i],b[i],0);
V.clear();
}for(int i=1;i<=n;i++)printf("%d ",f[i]);
return 0;
}

浙公网安备 33010602011771号