WQS 二分
引入:
- Problem: 有
个物品,恰好选出其中 个物品,最大化价值总和。
这个问题容易通过贪心解决。但是我们现在要考虑
接下来是
我们令
我们发现若没有
如果我们将所有的
于是我们进而考虑最大化该直线的截距,若我们取的点是
但是我们要求的是
例题:P5633 最小度限制生成树
显然答案具有下凸性,反证法不难证明。
于是我们二分斜率
注意有一个特殊的情况:当凸包上有三点共线的情况时,我们可能切不到
代码注意细节。
code:
qwq
#include<bits/stdc++.h> #define int long long #define eq(i) ((edges[i].u == s) || (edges[i].v == s)) using namespace std; const int N = 5e5 + 10; struct edge{ int u, v, w; }edges[N]; int n, m, s, k; int fa[N], gp, res, cnt, inf = 5e4; int findfa(int u){return fa[u] = (fa[u] == u) ? u : findfa(fa[u]);} bool cmp(struct edge e1, struct edge e2){ if(e1.w != e2.w) return e1.w < e2.w; return (e1.u == s) || (e1.v == s);//注意此处我们让含有 s 的尽量排在前面 } void calc(int slope){ for(int i = 1; i <= n; i++) fa[i] = i; for(int i = 1; i <= m; i++) if(eq(i)) edges[i].w -= slope; sort(edges + 1, edges + m + 1, cmp); cnt = gp = res = 0; for(int i = 1; i <= m; i++){ int fu = findfa(edges[i].u), fv = findfa(edges[i].v); if(fu == fv) continue; cnt++; gp += eq(i); res += edges[i].w; fa[fu] = fv; } for(int i = 1; i <= m; i++) if(eq(i)) edges[i].w += slope; } signed main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> n >> m >> s >> k; for(int i = 1; i <= m; i++){ int u, v, w; cin >> u >> v >> w; edges[i] = {u, v, w}; } calc(inf); if(k > gp){cout << "Impossible"; return 0;} calc(-inf);if(k < gp){cout << "Impossible"; return 0;} int l = -inf, r = inf; while(l + 1 < r){ int mid = (l + r) >> 1; calc(mid); if(gp < k) l = mid; else r = mid; } calc(r); cout << res + r * k; return 0; }
本文作者:Little_corn
本文链接:https://www.cnblogs.com/little-corn/p/18226082
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步