Weighted dichotomy (wqs dichotomy)

Posted by gskaruz on Sun, 20 Feb 2022 19:40:26 +0100

I think I'm original

Applicable question types and ideas

Find the maximum value of the sum of contributions, but it limits that something must be selected exactly k k k

It's easy to do without a number limit

Bring something with restrictions and add a hypothetical contribution In other words, if we choose one of these things, we add it to the total contribution of our calculated answers δ \delta δ.

δ \delta δ The larger, the more / less of this thing you may choose

In this way, we can split δ \delta δ, Make the right choice k k k, and then subtract the imaginary part from the contribution

Example: [national training team 2]Tree I

Luogu

Give you an undirected weighted connected graph with black or white edges Let you ask for a tree with the least weight n e e d need need a spanning tree with white edges

The edge weight is an integer The problem is guaranteed to be solved

n ≤ 5 ⋅ 1 0 4 , m ≤ 1 0 5 , 1 ≤ w ≤ 100 n \le 5 \cdot 10^4, m \le 10^5, 1 \le w \le 100 n≤5⋅104,m≤105,1≤w≤100

thinking

Think first:

To kruskal this tree, we need to sort the edges by weight However, MST made only by weight ranking does not happen to have n e e d need need a spanning tree with white edges Therefore, we should "disrupt the sorting rules" and make the white edge a little closer to the front or back

How to modify the position of the white edge?

We also find that the white edge is also the edge with the smaller weight Therefore, try to modify the weights of all white edges and add them all δ \delta δ, Then do MST

It can be found that with δ \delta δ The number of white edges obtained with the increase of w w w decreases (not strictly), that is, it is monotonic So two points δ \delta δ It can be solved

The final answer is that the MST result we seek should be subtracted w ( n e e d ) ⋅ δ w(need) \cdot \delta w(need)⋅δ

details

Note that the edge weight is an integer, δ \delta δ It should also take an integer, which is the half of an integer So there's a problem, δ 0 \delta_0 δ At 0 °, w > n e e d w > need w>need; δ 0 + 1 \delta_0 + 1 δ At 0 + 1, w < n e e d w < need W < need, no point can just make w w w get n e e d need need.

When we modify the edge weight of a white edge to k k When k, it happens that the edge right of several black edges is also k k k. If our order is to take the white edge first when the edge weights are equal So at this time w w w is relative to the previous one w l a s t w_{last} wlast# changes by more than 1 That's why you can't just get it n e e d need The reason for need Equal weights give priority to black edges also has the same problem

The solution is: the weight is equal and the white edge is preferred So two points for each δ \delta δ Corresponding w w In w, take the first one greater than or equal to n e e d need need w 1 w_1 w1, let the last be less than n e e d need The of need is w 0 w_0 w0​; If w 1 > n e e d w_1 > need w1 > need and w 0 < n e e d w_0 < need w0 < need, it is proved that there are black edges and white edges with equal weight At this time, we only need to replace several white edges with black edges, so that the MST value remains unchanged, but what we need to subtract when we finally calculate the answer is n e e d ⋅ δ need \cdot \delta need⋅ δ (not w ⋅ δ w \cdot \delta w⋅δ).

{{% code %}}

const int MAXN = 1e5+10;
const int WHITE = 0;
const int BLACK = 1;

struct Edge {
int u, v, w;
bool operator < (const Edge &E) {
return w < E.w;
}
} edges[2][MAXN];
int mm[2];

int n, m, need, ans;

int fa[MAXN];
void init() {
for (int i = 1; i <= n; i++)
fa[i] = i;
}
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
void uni(int x, int y) {
fa[find(x)] = find(y);
}

int check(int delta, int &res) {
init();
res = 0;
int w = 0, i = 1, j = 1;
while (i <= mm[WHITE] && j <= mm[BLACK]) {
if (edges[WHITE][i].w + delta <= edges[BLACK][j].w) {
if (find(edges[WHITE][i].u) != find(edges[WHITE][i].v)) {
w++, res += edges[WHITE][i].w + delta;
uni(edges[WHITE][i].u, edges[WHITE][i].v);
}
i++;
}
else {
if (find(edges[BLACK][j].u) != find(edges[BLACK][j].v)) {
res += edges[BLACK][j].w;
uni(edges[BLACK][j].u, edges[BLACK][j].v);
}
j++;
}
}
while (i <= mm[WHITE]) {
if (find(edges[WHITE][i].u) != find(edges[WHITE][i].v)) {
w++, res += edges[WHITE][i].w + delta;
uni(edges[WHITE][i].u, edges[WHITE][i].v);
}
i++;
}
while (j <= mm[BLACK]) {
if (find(edges[BLACK][j].u) != find(edges[BLACK][j].v)) {
res += edges[BLACK][j].w;
uni(edges[BLACK][j].u, edges[BLACK][j].v);
}
j++;
}
return w;
}

int main() {
scanf("%d%d%d", &n, &m, &need);
for (int i = 1; i <= m; i++) {
int u, v, w, c;
scanf("%d%d%d%d", &u, &v, &w, &c);
u++, v++;
edges[c][++mm[c]] = Edge{u, v, w};
}
sort(edges[WHITE]+1, edges[WHITE]+mm[WHITE]+1);
sort(edges[BLACK]+1, edges[BLACK]+mm[BLACK]+1);
int l = -101, r = 101;
while (l <= r) {
int mid = (l+r) >> 1, sum = 0, w = 0;
if ((w = check(mid, sum)) >= need) {
ans = sum - need * mid;
l = mid + 1;
}
else
r = mid - 1;
}
printf("%d\n", ans);
return 0;
}


{{% /code %}}

summary

A routine that matches the title

• Find the maximum value of the sum of contributions
• It restricts the choice of something k k k
• It's easy to do without a number limit
• Bring something with restrictions to an additional contribution δ \delta δ, And δ \delta δ The larger, the more / less of this thing you may choose

You can use it directly

Then we should pay attention to the selection conditions. When the contribution of this thing is equal to that of not selecting it, select it, and the score is greater than or equal to two k k The answer to the first number of k minus k δ k\delta k δ All right