对于每个哨站
i
i
i 建立点
i
1
i_1
i1 和
i
2
i_2
i2,连边
(
s
,
i
1
,
1
,
0
)
,
(
i
2
,
t
,
1
,
0
)
,
(
i
1
,
t
,
1
,
w
)
(s,i_1,1,0),(i_2,t,1,0),(i_1,t,1,w)
(s,i1,1,0),(i2,t,1,0),(i1,t,1,w)。
对于每两个哨站
i
,
j
(
j
<
i
)
i,j(j<i)
i,j(j<i),连边
(
i
1
,
j
2
,
1
,
∣
a
[
i
]
−
a
[
j
]
∣
)
(i_1,j_2,1,|a[i]-a[j]|)
(i1,j2,1,∣a[i]−a[j]∣)。
然后
s
→
t
s→t
s→t 的最小费用最大流就是答案。
但是这样建图边数是
O
(
n
2
)
O(n^2)
O(n2) 的,需要优化。
考虑分治建图:对于区间
[
l
,
r
]
[l,r]
[l,r],我们考虑建立
x
1
→
y
2
(
x
∈
[
l
,
m
i
d
]
,
y
∈
[
m
i
d
+
1
,
r
]
)
x_1→y_2(x∈[l,mid],y∈[mid+1,r])
x1→y2(x∈[l,mid],y∈[mid+1,r])的路径使得与原图等价。
我们新建
r
−
l
+
1
r-l+1
r−l+1 个点,第
i
i
i 个点的权值为
a
[
l
+
i
−
1
]
a[l+i-1]
a[l+i−1]。
把这
r
−
l
+
1
r-l+1
r−l+1 个点按权值升序排序,离散化。
对于排序后的任意相邻两点
u
,
v
u,v
u,v,连边
(
u
,
v
,
∞
,
v
的
权
值
−
u
的
权
值
)
(u,v,∞,v的权值-u的权值)
(u,v,∞,v的权值−u的权值)。
然后对于每个
x
1
(
x
∈
[
l
,
m
i
d
]
)
x_1(x∈[l,mid])
x1(x∈[l,mid]),在新建的点当中找到权值与
a
[
x
]
a[x]
a[x] 相等的点
u
u
u,连边
(
x
1
,
u
,
1
,
0
)
(x_1,u,1,0)
(x1,u,1,0)。
同理,对于每个
y
2
(
y
∈
[
m
i
d
+
1
,
r
]
)
y_2(y∈[mid+1,r])
y2(y∈[mid+1,r]),在新建的点当中找到权值与
a
[
y
]
a[y]
a[y] 相等的点
v
v
v,连边
(
v
,
y
2
,
1
,
0
)
(v,y_2,1,0)
(v,y2,1,0)。
显然这样连边使得
x
1
→
y
2
x_1→y_2
x1→y2 路径上的费用之和还是
∣
a
[
x
]
−
a
[
y
]
∣
|a[x]-a[y]|
∣a[x]−a[y]∣。
接着我们分别递归区间
[
l
,
m
i
d
]
,
[
m
i
d
+
1
,
r
]
[l,mid],[mid+1,r]
[l,mid],[mid+1,r],重复上述步骤。
这样我们就建立了一张和原图等价的新图,但是边数优化为
O
(
n
log
n
)
O(n \log n)
O(nlogn)。
Code
#include<bits/stdc++.h>usingnamespace std;#define ll long longtemplate<classt>inlinevoidread(t & res){char ch;while(ch =getchar(),!isdigit(ch));
res = ch ^48;while(ch =getchar(),isdigit(ch))
res = res *10+(ch ^48);}constint e =1e6+5, inf1 =0x3f3f3f3f;const ll inf2 =0x3f3f3f3f3f3f3f3fll;int a[e], adj[e], nxt[e], go[e], num =1, c[e], f[e], w, s, t, pool, b[e], tot, n;bool vis[e], walk[e];
ll co[e], dist[e], ans;inlinevoidadd(int x,int y,int v,int w){
nxt[++num]= adj[x];
adj[x]= num;
go[num]= y;
c[num]= v;
co[num]= w;
nxt[++num]= adj[y];
adj[y]= num;
go[num]= x;
co[num]=-w;}inlineboolbfs(){
deque<int>q;int i;for(i =1; i <= t; i++) walk[i]=0, dist[i]= inf2;
q.push_front(s);
dist[s]=0;while(!q.empty()){int u = q.front();
q.pop_front();
vis[u]=0;for(i = adj[u]; i; i = nxt[i]){int v = go[i];if(dist[v]> dist[u]+ co[i]&& c[i]> f[i]){
dist[v]= dist[u]+ co[i];if(!vis[v]){
vis[v]=1;if(q.empty()|| dist[v]< dist[q.front()]) q.push_front(v);else q.push_back(v);}}}}return dist[t]< inf2;}inlineintdfs(int u,int a){if(u == t || a ==0){
ans += dist[t]* a;return a;}int i, flow =0, f1;
walk[u]=1;for(i = adj[u]; i; i = nxt[i]){int v = go[i];if(dist[v]== dist[u]+ co[i]&& c[i]> f[i]&&!walk[v]){
f1 =dfs(v,min(c[i]- f[i], a));if(f1){
f[i]+= f1;
f[i ^1]-= f1;
flow += f1;
a -= f1;if(a ==0)break;}}}return flow;}inlinevoidinit(int l,int r){if(l == r)return;int i, mid = l + r >>1;
tot =0;for(i = l; i <= r; i++) b[++tot]= a[i];sort(b +1, b + tot +1);
tot =unique(b +1, b + tot +1)- b -1;for(i =1; i < tot; i++){add(pool + i, pool + i +1, inf1, b[i +1]- b[i]);add(pool + i +1, pool + i, inf1, b[i +1]- b[i]);}for(i = mid +1; i <= r; i++){int pos =lower_bound(b +1, b + tot +1, a[i])- b;add(i, pool + pos,1,0);}for(i = l; i <= mid; i++){int pos =lower_bound(b +1, b + tot +1, a[i])- b;add(pool + pos, i + n,1,0);}
pool += tot;init(l, mid);init(mid +1, r);}intmain(){int i;read(n);read(w);for(i =1; i <= n; i++)read(a[i]);
pool =2* n;init(1, n);
s = pool +1; t = s +1;for(i =1; i <= n; i++)add(s, i,1,0),add(i + n, t,1,0),add(i, t,1, w);while(bfs())dfs(s, inf1);
cout << ans << endl;return0;}