https://vj.imken.moe/contest/597216#problem/I
题目等价于求 min ∑ u a u ( o u t u − i n u ) \min \sum_{u}a_u(out_u-in_u) min∑uau(outu−inu)
发现每个数的取值范围最多到 n n n,然后又有一堆限制,考虑拆点+网络流。
每个点拆成 n + 2 n+2 n+2 个点(分别代表取值从 0 ∼ n + 1 0\sim n+1 0∼n+1),代表他的 n n n 种取值,然后我们现在要是代价最小,我们考虑最小割,考虑下图连边方式:
我们考虑这个点选了 3 ( k ) 3(k) 3(k),看一下割的效果
也就是 k × o u t u + ( n + 1 − k ) × i n u = k × ( o u t u − i n u ) + ( n + 1 ) × i n u k\times out_u+(n+1-k)\times in_u=k\times (out_u-in_u)+(n+1)\times in_u k×outu+(n+1−k)×inu=k×(outu−inu)+(n+1)×inu
现在我们还要满足 a u > a v a_u>a_v au>av,我们在所以 ( u , k ) → ( v , k − 1 ) (u,k)\to(v,k-1) (u,k)→(v,k−1) 中连边即可。
然后构造最小割输出即可。
#include<bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stdout, ##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
#define int long long
inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||
ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
#define fi first
#define se second
//srand(time(0));
#define N 100010
//#define M
//#define mo
namespace Flow {
#define int long long
struct mf_graph {
struct node {
int x, y, z, n;
};
vector<node>d;
vector<int>h, H, dep;
queue<int>q;
int k;
int u, v, w, S, T, ans=0;
void reset(int n) {
h.resize(n+5); k=1; d.resize(2);
H.resize(n+5); dep.resize(n+5);
}
void cun(int x, int y, int z) {
++k; d.pb({x, y, z, h[x]});
d[k].n=h[x]; h[x]=k;
}
void add_edge(int x, int y, int z) {
if(x!=1 && y!=2)debug("%lld %lld %lld\n", x, y, z);
// debug("%lld -> %lld %lld\n", x, y, z);
cun(x, y, z); cun(y, x, 0);
}
int bfs() {
while(!q.empty()) q.pop();
fill(dep.begin(), dep.end(), -1);
h=H;
dep[S]=1; q.push(S);
while(!q.empty()) {
u=q.front(); q.pop();
for(int g=h[u]; g; g=d[g].n) {
v=d[g].y; w=d[g].z;
if(w<=0 || dep[v]!=-1) continue;
dep[v]=dep[u]+1; q.push(v);
}
}
return dep[T]!=-1;
}
int dfs(int x, int w) {
if(x==T) return w;
if(!w) return 0;
int ans=0, s;
for(int &i=h[x]; i; i=d[i].n) {
int y=d[i].y, z=d[i].z;
if(dep[y]!=dep[x]+1) continue;
if(z<=0) continue;
s=dfs(y, min(w, z)); ans+=s; w-=s;
d[i].z-=s; d[i^1].z+=s;
if(!w) break;
}
return ans;
}
int flow(int SS, int TT) {
S=SS; T=TT; H=h;
while(bfs()) ans+=dfs(S, 1e18);
return ans;
}
};
#undef int
}
using namespace Flow;
int n, m, i, j, k, T, S;
int ans[N], u, v, w, Out[N], In[N];
int nd(int i, int j) {
return i*100+j;
}
signed main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
// T=read();
// while(T--) {
//
// }
n=read(); m=read();
mf_graph G; G.reset(1000010);
S=1; T=2;
for(i=1; i<=m; ++i) {
u=read(); v=read(); w=read();
Out[u]+=w; In[v]+=w; k-=In[v];
for(j=1; j<=n+1; ++j)
G.add_edge(nd(u, j), nd(v, j-1), 1e18);
}
for(i=1; i<=n; ++i) {
for(j=0; j<=n+1; ++j) G.add_edge(S, nd(i, j), Out[i]);
for(j=0; j<=n+1; ++j) G.add_edge(nd(i, j), T, In[i]);
for(j=0; j<=n; ++j) G.add_edge(nd(i, j), nd(i, j+1), 1e18);
G.add_edge(S, nd(i, n+1), 1e18); G.add_edge(nd(i, 0), T, 1e18);
}
k*=(n+1); k+=G.flow(S, T);
debug(">> %lld\n", k);
G.bfs();
for(i=1; i<=n; ++i) {
for(j=n; j>=0; --j) if(G.dep[nd(i, j)]==-1) break;
ans[i]=j;
}
for(i=1; i<=n; ++i) printf("%lld ", ans[i]);
return 0;
}