Skip to content

Commit

Permalink
smawk
Browse files Browse the repository at this point in the history
  • Loading branch information
potato167 committed Jul 14, 2024
1 parent c0b0f9c commit dce30cf
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 0 deletions.
71 changes: 71 additions & 0 deletions algorithm/smawk.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#pragma once
#include <vector>
#include <numeric>
namespace po167{
// return argmax
//
// https://noshi91.github.io/Library/algorithm/smawk.cpp
template<class S> std::vector<int> smawk(int N, int M, S select){
auto f = [&](auto self, std::vector<int> p,std::vector<int> q) -> std::vector<int> {
// reduce
std::vector<int> n_q;
n_q.reserve(p.size());
int k = -1;
for(auto x:q){
while(!n_q.empty()){
if(!select(p[k], n_q.back(), x)) break;
n_q.pop_back();
k--;
}
if (k + 1 != (int)p.size()){
n_q.push_back(x);
k++;
}
}
std::swap(n_q, q);

int n = p.size();
int m = q.size();

// recursive
if (n == 1){
return q;
}
std::vector<int> n_p;
n_p.reserve(n / 2);

for (int i = 1; i < n; i += 2){
n_p.push_back(p[i]);
}

auto fr = self(self, n_p, q);
// interpolate
std::vector<int> ans(n);
int l = 0, r = 0;

for (int i = 0; i < n; i++){
if(i & 1){
ans[i] = fr[i / 2];
l = r;
} else {
if (i + 1 != n) {
while (q[r] != fr[i / 2]) r++;
} else {
r = m - 1;
}
ans[i] = q[l];
for (int j = l + 1; j <= r; j++){
if(select(p[i], ans[i], q[j])){
ans[i] = q[j];
}
}
}
}
return ans;
};
std::vector<int> P(N), Q(M);
std::iota(P.begin(), P.end(), 0);
std::iota(Q.begin(), Q.end(), 0);
return f(f, P, Q);
}
}
38 changes: 38 additions & 0 deletions algorithm/sum_max_convolution.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#pragma once
#include <vector>
#include <algorithm>
#include "smawk.hpp"

namespace po167{
// X is convex upward
template<class T>
std::vector<T> sum_max_convolution(std::vector<T> X, std::vector<T> Y){
int n = X.size();
int m = Y.size();
std::vector<T> ans(n + m - 1);
auto get = [&](int i, int j) -> T {
return X[i - j] + Y[j];
};
auto select = [&](int i, int j1, int j2) -> bool {
if (i < j2) return false;
if (i - j1 >= n) return true;
return get(i, j1) <= get(i, j2);
};
const int D = 10;
if (std::min(n, m) <= D) {
for (int i = 0; i < n + m - 1; i++){
int ind = std::max(0, i - n);
for (int j = ind + 1; j < m && j <= i; j++){
if (select(i, ind, j)) ind = j;
}
ans[i] = get(i, ind);
}
return ans;
}
std::vector<int> res = smawk(n + m - 1, m, select);
for (int i = 0; i < n + m - 1; i++){
ans[i] = get(i, res[i]);
}
return ans;
}
}
22 changes: 22 additions & 0 deletions test/algorithm/sum_min_conv.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#define PROBLEM https://judge.yosupo.jp/problem/min_plus_convolution_convex_arbitrary

Check failure on line 1 in test/algorithm/sum_min_conv.test.cpp

View workflow job for this annotation

GitHub Actions / build

failed to verify

#include "../../algorithm/sum_max_convolution.hpp"

#include <iostream>
#include <vector>

int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int N, M;
std::cin >> N >> M;
std::vector<int> A(N), B(M);
for (auto &a : A) std::cin >> a, a *= -1;
for (auto &b : B) std::cin >> b, b *= -1;
auto c = po167::sum_max_convolution(A, B);
for (int i = 0; i < N + M - 1; i++){
if (i) std::cout << " ";
std::cout << -c[i];
}
std::cout << "\n";
}

0 comments on commit dce30cf

Please sign in to comment.