ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

关于wqs二分(凸优化) 实数二分和整数二分的一些讨论

2020-03-31 23:00:45  阅读:415  来源: 互联网

标签:二分 pii fs 斜率 实数 wqs int se define


https://loj.ac/problem/2478

以上面这题为例,这道题斜率是不递增的,并且都是整数。

实数二分很爽,但是效率不高,对于斜率都是整数的,我们可以采用整数二分,但是需要注意一点细节:

wqs二分,是找一个斜率,使得第k个成为最优点。

但是,因为斜率可能出现一段相同的情况,因此可能有一个斜率,使得一干点同时成为最优,我们要第k个被包含在其中,这样就没有办法恰好找到了。

此时,在dp的过程,应该保证权值和相同时,选的点数尽可能多,这样找到一个斜率ans使得最优点恰好\(>=k\),真正答案就是\(dp值+ans*k\)。

“权值和相同时,选的点数尽可能多”是必要的,因为假设k在一段斜率相同的中间,而dp出的点数总是在k的左边,这样就会取到下一个斜率,就不是最优了。

参考代码:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

#define V vector<int>
#define pb push_back
#define si size()

const int N = 3e5 + 5;

int n, k, x, y, z;
int fi[N * 2], nt[N * 2], to[N * 2], v[N * 2], tot;

void link(int x, int y, int z) {
	nt[++ tot] = fi[x], to[tot] = y, v[tot] = z, fi[x] = tot;
}

#define pii pair<ll, int>
#define fs first
#define se second

int fa[N];
pii f[N][3], g[N][3];

ll w;

pii mv(pii a, pii b) {
	if(a.fs == b.fs) return a.se > b.se ? a : b;
	return a.fs > b.fs ? a : b;
}

pii operator + (pii a, pii b) {
	return pii(a.fs + b.fs, a.se + b.se);
}

void dg(int x) {
	f[x][0] = w < 0 ? pii(0, 0) : pii(w, 1);
	f[x][1] = pii(w, 1);
	f[x][2] = pii(w, 1);
	
	for(int i = fi[x]; i; i = nt[i]) {
		int y = to[i], z = v[i];
		if(y == fa[x]) continue;
		fa[y] = x;
		dg(y);
		
		g[x][2] = f[x][2] + f[y][0];
		
		g[x][1] = f[x][1] + f[y][0];
		pii d = f[x][2] + f[y][1];
		d.se --; d.fs += z - w;
		g[x][1] = mv(g[x][1], d);
		
		g[x][0] = f[x][0] + f[y][0];
		d = f[x][1] + f[y][1];
		d.se --; d.fs += z - w;
		g[x][0] = mv(g[x][0], d);
		
		f[x][0] = mv(g[x][0], mv(g[x][1], g[x][2]));
		f[x][1] = mv(g[x][1], g[x][2]);
		f[x][2] = g[x][2];
	}
}

int count(ll _w) {
	w = _w;
	dg(1);
	return f[1][0].se;
}

int main() {
	scanf("%d %d", &n, &k); k ++;
	fo(i, 1, n - 1) {
		scanf("%d %d %d", &x, &y, &z);
		link(x, y, z); link(y, x, z);
	}
	ll ans = 0;
	for(ll l = -3e11, r = 3e11; l <= r; ) {
		ll m = l + r >> 1;
		if(count(m) >= k) ans = m, r = m - 1; else l = m + 1;
	}
	count(ans);
	pp("%lld\n", f[1][0].fs - k * ans);
}

标签:二分,pii,fs,斜率,实数,wqs,int,se,define
来源: https://www.cnblogs.com/coldchair/p/12609384.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有