This documentation is automatically generated by online-judge-tools/verification-helper
#include "flow/k-ary-optimization.hpp"
#pragma once
#include "flow/dinic.hpp"
/**
* Author: Teetat T.
* Date: 2024-07-16
* Description: k-ary Optimization.
* minimize $\kappa + \sum_i \theta_i(x_i) + \sum_{i<j} \phi_{ij}(x_i,x_j)$
* where $x_i \in \{0,1,\ldots,k-1\}$ and $\phi_{i,j}$ is monge.
* A function $f$ is monge if $f(a,c)+f(b,d) \leq f(a,d)+f(b,c)$ for all $a < b$ and $c < d$.
* $\phi_{ij}(x-1,y)+\phi_{ij}(x,y+1) \leq \phi_{ij}(x-1,y+1)+\phi_{ij}(x,y)$.
* $\phi_{ij}(x,y)+\phi_{ij}(x-1,y+1)-\phi_{ij}(x-1,y)-\phi_{ij}(x,y+1) \geq 0$.
*/
template<class T,bool minimize=true>
struct K_aryOptimization{
static constexpr T INF=numeric_limits<T>::max()/2;
int n,s,t,node_id;
T base;
vector<int> ks;
vector<vector<int>> id;
map<pair<int,int>,T> edges;
K_aryOptimization(int n,int k){init(vector<int>(n,k));}
K_aryOptimization(const vector<int> &_ks){init(_ks);}
void init(const vector<int> &_ks){
ks=_ks;
n=ks.size();
s=0,t=1,node_id=2;
base=0;
id.clear();
edges.clear();
for(auto &k:ks){
assert(k>=1);
vector<int> a(k+1);
a[0]=s,a[k]=t;
for(int i=1;i<k;i++)a[i]=node_id++;
id.emplace_back(a);
for(int i=2;i<k;i++)add_edge(a[i],a[i-1],INF);
}
}
void add_edge(int u,int v,T w){
assert(w>=0);
if(u==v||w==0)return;
auto &e=edges[{u,v}];
e=min(e+w,INF);
}
void add0(T w){
base+=w;
}
void _add1(int i,vector<T> cost){
add0(cost[0]);
for(int j=1;j<ks[i];j++){
T x=cost[j]-cost[j-1];
if(x>0)add_edge(id[i][j],t,x);
if(x<0)add0(x),add_edge(s,id[i][j],-x);
}
}
void add1(int i,vector<T> cost){
assert(0<=i&&i<n&&(int)cost.size()==ks[i]);
if(!minimize)for(auto &x:cost)x=-x;
_add1(i,cost);
}
void _add2(int i,int j,vector<vector<T>> cost){
int h=ks[i],w=ks[j];
_add1(j,cost[0]);
for(int x=h-1;x>=0;x--)for(int y=0;y<w;y++)cost[x][y]-=cost[0][y];
vector<T> a(h);
for(int x=0;x<h;x++)a[x]=cost[x][w-1];
_add1(i,a);
for(int x=0;x<h;x++)for(int y=0;y<w;y++)cost[x][y]-=a[x];
for(int x=1;x<h;x++){
for(int y=0;y<w-1;y++){
T w=cost[x][y]+cost[x-1][y+1]-cost[x-1][y]-cost[x][y+1];
assert(w>=0); // monge
add_edge(id[i][x],id[j][y+1],w);
}
}
}
void add2(int i,int j,vector<vector<T>> cost){
assert(0<=i&&i<n&&0<=j&&j<n&&i!=j);
assert((int)cost.size()==ks[i]);
for(auto &v:cost)assert((int)v.size()==ks[j]);
if(!minimize)for(auto &v:cost)for(auto &x:v)x=-x;
_add2(i,j,cost);
}
pair<T,vector<int>> solve(){
Dinic<T> dinic(node_id,s,t);
for(auto &[p,w]:edges){
auto [u,v]=p;
dinic.add_edge(u,v,w);
}
auto [val,cut]=dinic.cut();
val+=base;
if(!minimize)val=-val;
vector<int> ans(n);
for(int i=0;i<n;i++){
ans[i]=ks[i]-1;
for(int j=1;j<ks[i];j++)ans[i]-=cut[id[i][j]];
}
return {val,ans};
}
};
#line 2 "flow/dinic.hpp"
/**
* Author: Teetat T.
* Date: 2024-07-15
* Description: Dinic's Algorithm for finding the maximum flow.
* Time: O(V E \log U) where U is the maximum flow.
*/
template<class T,bool directed=true,bool scaling=true>
struct Dinic{
static constexpr T INF=numeric_limits<T>::max()/2;
struct Edge{
int to;
T flow,cap;
Edge(int _to,T _cap):to(_to),flow(0),cap(_cap){}
T remain(){return cap-flow;}
};
int n,s,t;
T U;
vector<Edge> e;
vector<vector<int>> g;
vector<int> ptr,lv;
bool calculated;
T max_flow;
Dinic(){}
Dinic(int n,int s,int t){init(n,s,t);}
void init(int _n,int _s,int _t){
n=_n,s=_s,t=_t;
U=0;
e.clear();
g.assign(n,{});
calculated=false;
}
void add_edge(int from,int to,T cap){
assert(0<=from&&from<n&&0<=to&&to<n);
g[from].emplace_back(e.size());
e.emplace_back(to,cap);
g[to].emplace_back(e.size());
e.emplace_back(from,directed?0:cap);
U=max(U,cap);
}
bool bfs(T scale){
lv.assign(n,-1);
vector<int> q{s};
lv[s]=0;
for(int i=0;i<(int)q.size();i++){
int u=q[i];
for(int j:g[u]){
int v=e[j].to;
if(lv[v]==-1&&e[j].remain()>=scale){
q.emplace_back(v);
lv[v]=lv[u]+1;
}
}
}
return lv[t]!=-1;
}
T dfs(int u,int t,T f){
if(u==t||f==0)return f;
for(int &i=ptr[u];i<(int)g[u].size();i++){
int j=g[u][i];
int v=e[j].to;
if(lv[v]==lv[u]+1){
T res=dfs(v,t,min(f,e[j].remain()));
if(res>0){
e[j].flow+=res;
e[j^1].flow-=res;
return res;
}
}
}
return 0;
}
T flow(){
if(calculated)return max_flow;
calculated=true;
max_flow=0;
for(T scale=scaling?1LL<<(63-__builtin_clzll(U)):1LL;scale>0;scale>>=1){
while(bfs(scale)){
ptr.assign(n,0);
while(true){
T f=dfs(s,t,INF);
if(f==0)break;
max_flow+=f;
}
}
}
return max_flow;
}
pair<T,vector<int>> cut(){
flow();
vector<int> res(n);
for(int i=0;i<n;i++)res[i]=(lv[i]==-1);
return {max_flow,res};
}
};
#line 3 "flow/k-ary-optimization.hpp"
/**
* Author: Teetat T.
* Date: 2024-07-16
* Description: k-ary Optimization.
* minimize $\kappa + \sum_i \theta_i(x_i) + \sum_{i<j} \phi_{ij}(x_i,x_j)$
* where $x_i \in \{0,1,\ldots,k-1\}$ and $\phi_{i,j}$ is monge.
* A function $f$ is monge if $f(a,c)+f(b,d) \leq f(a,d)+f(b,c)$ for all $a < b$ and $c < d$.
* $\phi_{ij}(x-1,y)+\phi_{ij}(x,y+1) \leq \phi_{ij}(x-1,y+1)+\phi_{ij}(x,y)$.
* $\phi_{ij}(x,y)+\phi_{ij}(x-1,y+1)-\phi_{ij}(x-1,y)-\phi_{ij}(x,y+1) \geq 0$.
*/
template<class T,bool minimize=true>
struct K_aryOptimization{
static constexpr T INF=numeric_limits<T>::max()/2;
int n,s,t,node_id;
T base;
vector<int> ks;
vector<vector<int>> id;
map<pair<int,int>,T> edges;
K_aryOptimization(int n,int k){init(vector<int>(n,k));}
K_aryOptimization(const vector<int> &_ks){init(_ks);}
void init(const vector<int> &_ks){
ks=_ks;
n=ks.size();
s=0,t=1,node_id=2;
base=0;
id.clear();
edges.clear();
for(auto &k:ks){
assert(k>=1);
vector<int> a(k+1);
a[0]=s,a[k]=t;
for(int i=1;i<k;i++)a[i]=node_id++;
id.emplace_back(a);
for(int i=2;i<k;i++)add_edge(a[i],a[i-1],INF);
}
}
void add_edge(int u,int v,T w){
assert(w>=0);
if(u==v||w==0)return;
auto &e=edges[{u,v}];
e=min(e+w,INF);
}
void add0(T w){
base+=w;
}
void _add1(int i,vector<T> cost){
add0(cost[0]);
for(int j=1;j<ks[i];j++){
T x=cost[j]-cost[j-1];
if(x>0)add_edge(id[i][j],t,x);
if(x<0)add0(x),add_edge(s,id[i][j],-x);
}
}
void add1(int i,vector<T> cost){
assert(0<=i&&i<n&&(int)cost.size()==ks[i]);
if(!minimize)for(auto &x:cost)x=-x;
_add1(i,cost);
}
void _add2(int i,int j,vector<vector<T>> cost){
int h=ks[i],w=ks[j];
_add1(j,cost[0]);
for(int x=h-1;x>=0;x--)for(int y=0;y<w;y++)cost[x][y]-=cost[0][y];
vector<T> a(h);
for(int x=0;x<h;x++)a[x]=cost[x][w-1];
_add1(i,a);
for(int x=0;x<h;x++)for(int y=0;y<w;y++)cost[x][y]-=a[x];
for(int x=1;x<h;x++){
for(int y=0;y<w-1;y++){
T w=cost[x][y]+cost[x-1][y+1]-cost[x-1][y]-cost[x][y+1];
assert(w>=0); // monge
add_edge(id[i][x],id[j][y+1],w);
}
}
}
void add2(int i,int j,vector<vector<T>> cost){
assert(0<=i&&i<n&&0<=j&&j<n&&i!=j);
assert((int)cost.size()==ks[i]);
for(auto &v:cost)assert((int)v.size()==ks[j]);
if(!minimize)for(auto &v:cost)for(auto &x:v)x=-x;
_add2(i,j,cost);
}
pair<T,vector<int>> solve(){
Dinic<T> dinic(node_id,s,t);
for(auto &[p,w]:edges){
auto [u,v]=p;
dinic.add_edge(u,v,w);
}
auto [val,cut]=dinic.cut();
val+=base;
if(!minimize)val=-val;
vector<int> ans(n);
for(int i=0;i<n;i++){
ans[i]=ks[i]-1;
for(int j=1;j<ks[i];j++)ans[i]-=cut[id[i][j]];
}
return {val,ans};
}
};