题解:[JOI2025 预选赛 R2] 亲密的厨师 / Intimate Chef

题目传送门

题意分析

首先发现 \(a,b\) 顺序与答案无关,以 \(a\) 为关键字排序,钦定 \(i<j\)\(a_i\leq a_j\)。对应地更改 \(b\) 的顺序。

钦定 \(j<i\)\((i,j)\) 的答案即为:

\[\max(a_i,a_j)+\max(b_i,b_j)=a_i+\max(b_i,b_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+\max\left(b_n,\max_{j<n}b_j\right) \]

之后,\(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;
}
posted @ 2026-07-08 15:51  TH911  阅读(1)  评论(0)    收藏  举报