题解:[JOI2025 预选赛 R2] 亲密的厨师 / Intimate Chef
题意分析
首先发现 \(a,b\) 顺序与答案无关,以 \(a\) 为关键字排序,钦定 \(i<j\) 时 \(a_i\leq a_j\)。对应地更改 \(b\) 的顺序。
钦定 \(j<i\),\((i,j)\) 的答案即为:
考虑接下来怎么做。一共有 \(\dfrac{n(n-1)}2\) 个答案,但是 \(m\) 组在其中就很讨厌。因此我们可以考虑求出前 \(\displaystyle\max_{i=1}^qx_i+m\) 大的答案后,去除 \(m\) 对 \((u_i,v_i)\) 的影响。(\((u_i,v_i)\) 的答案可能也不在这之中,那就保留)。因为 \(x_i\leq4\times10^5\),所以这种做法是可以接受的。
不难发现,最大的答案是:
之后,\(a_n\) 的答案已经回随着 \(j<i\) 的 \(b_j\) 减小而减小。推广到 \(\forall i\) 的答案 \(\displaystyle a_i+\max\left(b_i,\max_{j<i}b_j\right)\) 都是如此。
这启发我们针对确定的 \(a_i\),从大到小选取 \(j<i\) 的 \(b_j\) 后贪心即可。
将 \(b_1,b_2,\cdots,b_n\) 从小到大排序得到 \(b'_1,b'_2,\cdots,b'_n\)。记 \(b'_i\) 对应原 \(b\) 序列中的 \(\textit{idb}_i\)。
对于每一个 \(a_i\) 设计状态 \((i,j)\),表示其答案为 \(a_i+\max\left(a_i,b'_j\right)\)。
然后把每一个状态丢进一个大根堆里贪心即可。
更新就考虑找到一个 \(k<j\) 且 \(\textit{idb}_k<i\) 的最大的 \(k\),就得到了一个新的状态 \((i,k)\),继续丢进大根堆里贪心即可。
初始得到 \(a_1,a_2,\cdots,a_n\) 的状态时,可以在 \(b',\textit{idb}\) 上双指针,进而 \(\mathcal O(n\log n)\) 构造。
贪心过程中暴力跳的复杂度均摊后是对的。
时间复杂度 \(\mathcal O(n\log n)\)。
AC 代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
#include<set>
using namespace std;
constexpr const int N=4e5,M=4e5,X=4e5,inf=0x3f3f3f3f;
struct node{
int a,b,id;
}tmp[N+1];
pair<int,int>b[N+1];
int n,m,q,x[N+1],a[N+1],b0[N+1],id[N+1];
pair<int,int>g[M+1],preB0[N+1];
multiset<int>ans;
set<pair<int,int>>backup;
void solve(){
int k=x[1];
for(int i=2;i<=q;i++){
k=max(k,x[i]);
}
priority_queue<pair<int,pair<int,int>>>q;
for(int i=n,k=n;2<=i;i--){
while(b[k].second>=i){
k--;
}
if(!k){
break;
}
q.push({a[i]+max(b0[i],b[k].first),{i,k}});
}
while(q.size()){
auto [value,pl]=q.top();
auto [i,j]=pl;
q.pop();
ans.insert(value);
backup.insert({i,b[j].second});
if(ans.size()==k+m){
break;
}
for(int k=j-1;1<=k;k--){
if(b[k].second<i){
q.push({a[i]+max(b0[i],b[k].first),{i,k}});
break;
}
}
}
for(int i=1;i<=m;i++){
auto [u,v]=g[i];
u=id[u],v=id[v];
int value=max(a[u],a[v]) + max(b0[u],b0[v]);
if(backup.count({u,v})||backup.count({v,u})){
ans.erase(ans.lower_bound(value));
}
}
}
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m>>q;
for(int i=1;i<=n;i++){
cin>>tmp[i].a;
}
for(int i=1;i<=n;i++){
cin>>tmp[i].b;
tmp[i].id=i;
}
sort(tmp+1,tmp+n+1,[](node a,node b){
return a.a<b.a;
});
for(int i=1;i<=n;i++){
id[tmp[i].id]=i;
a[i]=tmp[i].a;
b[i]={tmp[i].b,i};
b0[i]=tmp[i].b;
}
sort(b+1,b+n+1,[](pair<int,int>a,pair<int,int>b){
return a.first<b.first;
});
for(int i=1;i<=m;i++){
cin>>g[i].first>>g[i].second;
}
for(int i=1;i<=q;i++){
cin>>x[i];
}
solve();
vector<int>ans0;
for(int x:ans){
ans0.push_back(x);
}
reverse(ans0.begin(),ans0.end());
for(int i=1;i<=q;i++){
cout<<ans0[x[i]-1]<<'\n';
}
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}

浙公网安备 33010602011771号