【wqs 二分】AcWing 347. 野餐规划
好像没见到用 wqs 二分写的 emm,使用 wqs 二分的复杂度为 ,吊打这题。
不熟悉 wqs 二分的可以先看:
https://www.acwing.com/file_system/file/content/whole/index/content/5873556/
分析
记号约定: 为 ,也就是 , 为 点的最大度数。
对下凸壳二分斜率找切线。
切线即便是会与多个点相切也不要紧,我们找到最靠左的切点以及横坐标为 的点,求出它们的 坐标并取 即可。
而因为可能出现最小生成树在横坐标为 的点的左边的情况(这意味着我们可以直接求最小生成树),那么就对此求一遍最小生成树就是答案了。
更多细节见代码:
// Problem: 野餐规划
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/349/
// Memory Limit: 10 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define x first
#define y second
using pii = pair<int, int>;
using ll = long long;
#define int long long
inline void read(int &x){
int s=0; x=1;
char ch=getchar();
while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
x*=s;
}
const int N=1e5+5, M=1e6+50;
struct Edge{
int u, v, w;
bool operator < (const Edge &o)const{
return w<o.w;
}
}e[M], es[M], buf[M];
int tot, tots, totb;
int f[N];
int find(int x){
return x==f[x]? x: f[x]=find(f[x]);
}
int n, m, s, k;
int res, cnt;
int cal(int x){
rep(i,1,tots) es[i].w-=x;
res=0, totb=0;
rep(i,1,n) f[i]=i;
for(int i=1, j=1; i<=tots || j<=tot; ){
if(i>tots || j<=tot && e[j].w<=es[i].w) buf[++totb]=e[j++];
else buf[++totb]=es[i++];
}
cnt=0;
rep(i,1,totb){
int u=buf[i].u, v=buf[i].v, w=buf[i].w;
int pu=find(u), pv=find(v);
if(pu!=pv){
f[pu]=pv;
if(u==s || v==s) cnt++;
res+=w;
}
}
rep(i,1,tots) es[i].w+=x;
return cnt;
}
map<string, int> mp;
int get(string x){
if(!mp.count(x)) return mp[x]=++n;
return mp[x];
}
signed main(){
cin>>m;
s=1;
get("Park");
rep(i,1,m){
string su, sv; cin>>su>>sv;
int u, v, w;
u=get(su), v=get(sv);
read(w);
if(u==s || v==s) es[++tots]={u, v, w};
else e[++tot]={u, v, w};
}
rep(i,1,n) f[i]=i;
cin>>k;
sort(es+1, es+1+tots), sort(e+1, e+1+tot);
cal(0);
if(cnt<=k) return cout<<"Total miles driven: "<<res<<endl, 0;
int l=-30010, r=-l;
while(l<r){
int mid=l+r+1>>1;
if(cal(mid)<=k) l=mid;
else r=mid-1;
}
cal(l);
int t=res;
int fir=l*cnt, sec=1e9;
if(cal(30010)>=k) sec=l*k;
cout<<"Total miles driven: "<<t+min(fir, sec)<<endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】