BZOJ杂题选记(8.11-8.16)
P4204 奥运物流
这个是所谓贡献后效性的 dp 问题,详见 2009 年徐源盛的论文。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long double ldb;
const int N = 65;
int n, m, s[N];
vector<int> e[N];
ldb k, c[N], mi[N], dp[N][N][N], tmp[N][N];
void chmax(ldb &a, ldb b){ a = max(a, b); }
void dfs(int u, int d){
for(int i = 0; i <= m; ++i)
for(int j = 0; j <= d; ++j) dp[u][i][j] = c[u] * mi[j];
for(int v : e[u]){
dfs(v, d + 1);
memset(tmp, 0, sizeof(tmp));
for(int i = 0; i <= m; ++i){
for(int j = 0; j <= d; ++j){
for(int k = 0; k <= m - i; ++k){
chmax(tmp[i + k][j], dp[u][i][j] + dp[v][k][j + 1]);
if(k >= 1) chmax(tmp[i + k][j], dp[u][i][j] + dp[v][k - 1][1]);
}
}
}
for(int i = 0; i <= m; ++i){
for(int j = 0; j <= d; ++j)
dp[u][i][j] = tmp[i][j];
}
}
}
int main(){
cin.tie(nullptr)->sync_with_stdio(0);
cin >> n >> m >> k;
mi[0] = 1;
for(int i = 1; i <= n; ++i) cin >> s[i], mi[i] = mi[i - 1] * k;
for(int i = 1; i <= n; ++i) cin >> c[i];
int cnt = 1; ldb ans = 0;
--m;
for(int u = s[1]; u != 1; u = s[u]){
++cnt; memset(e, 0, sizeof(e));
if(s[u] == 1) ++m;
e[1].push_back(u);
// cout << u << '\n';
for(int i = 2; i <= n; ++i){
if(i == u) continue;
e[s[i]].push_back(i);
}
// for(int i = 1; i <= n; ++i){
// cout << i << ":\n";
// for(int j : e[i]) cout << j << ' ';
// cout << '\n';
// }
memset(dp, 0, sizeof(dp));
dfs(1, 0);
chmax(ans, dp[1][m][0] / (1 - mi[cnt]));
//cout << dp[1][m][0] << '\n';
//cout << '\n';
}
cout << fixed << setprecision(2) << ans;
return 0;
}
P4468 折纸
脑筋急转弯题。求对称点是 trivial 的。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long double ldb;
const ldb eps = 1e-6;
struct vec{
ldb x, y;
vec operator + (const vec b){ return {x + b.x, y + b.y}; }
vec operator - (const vec b){ return {x - b.x, y - b.y}; }
ldb len(){ return sqrt(x * x + y * y); }
}p[10][2];
ldb dot(vec a, vec b){ return a.x * b.x + a.y *b.y; }
ldb cross(vec a, vec b){ return a.x * b.y - a.y * b.x; }
vec sym(vec a, vec b, vec c){
vec p1 = b - a, p2 = c - a;
// cout << p1.x << ' ' << p1.y << ' ' << p2.x << ' ' << p2.y << '\n';
if(cross(p2, p1) >= -eps) return {-1e9, -1e9};
//cout << dot(p1, p2) / (p1.len() * p2.len()) << '\n';
ldb theta = acos(max(min(dot(p1, p2) / (p1.len() * p2.len()), (ldb)1.), (ldb)-1.));
//cout << theta << '\n';
ldb cost = cos(-2 * theta), sint = sin(-2 * theta);
vec tmp = {p2.x * cost - p2.y * sint, p2.x * sint + p2.y * cost};
return a + tmp;
}
int n, m, ans;
bool in(vec p){ return p.x > eps && p.x < 100 - eps && p.y > eps && p.y < 100 - eps; }
void dfs(int x, vec now){
if(x == 0) return void(ans += in(now));
vec tmp = sym(p[x][0], p[x][1], now);
if(tmp.x == -1e9) return;
dfs(x - 1, now);
// cout << now.x << ',' << now.y << ' ' << x << ' ' << tmp.x << ',' << tmp.y << '\n';
dfs(x - 1, tmp);
}
int main(){
cin.tie(nullptr)->sync_with_stdio(0);
cin >> n;
for(int i = 1; i <= n; ++i)
cin >> p[i][0].x >> p[i][0].y >> p[i][1].x >> p[i][1].y;
cin >> m;
for(int i = 1; i <= m; ++i){
vec x; cin >> x.x >> x.y;
ans = 0; dfs(n, x);
cout << ans << '\n';
}
return 0;
}
P4469 最优驾车
一个 trick, 当状态中有有理数时,可以考虑乘上分母的最小公倍数变成整数(通分)。精度问题调了两个小时......
Code
#include <bits/stdc++.h>
using namespace std;
typedef long double ldb;
const ldb eps = 1e-9, inf = 1e9;
const int N = 12, K = 2520;
int n, L, hor[N], col[N];
ldb cal(ldb v){ return 80 - 0.03 * v * v; }
ldb f[N][N][K * 20 + 5];
void chmin(ldb &a, ldb b){ a = min(a, b); }
ldb cvt(int t){ return 1. * t * L / K * 60. / 5.; }
int mceil(ldb t){ return (fabs(floor(t) - t) < eps ? floor(t) : ceil(t)); }
int main(){
cin.tie(nullptr)->sync_with_stdio(0);
cin >> n >> L;
for(int i = 1; i <= n; ++i) cin >> col[i];
for(int i = 1; i <= n; ++i) cin >> hor[i];
int xs, ys, xt, yt, t1, t2;
cin >> xs >> ys >> xt >> yt >> t1 >> t2;
int d = K * 20;
for(int i = 0; i <= n; ++i){
for(int j = 0; j <= n; ++j){
for(int k = 0; k <= d; ++k)
f[i][j][k] = inf;
}
}
f[xs][ys][0] = 0;
int dx = (xs <= xt ? 1 : -1), dy = (ys <= yt ? 1 : -1);
for(int i = xs; i * dx <= xt * dx; i += dx){
for(int j = ys; j * dy <= yt * dy; j += dy){
for(int t = 0; t <= d; ++t){
if(f[i][j][t] == inf) continue;
int nxti = i + dx, nxtj = j + dy;
for(int v = 1; v * 5 <= col[j]; v++){
if(t + K / v <= d)
chmin(f[nxti][j][t + K / v], f[i][j][t] + L / cal(v * 5));
}
for(int v = 1; v * 5 <= hor[i]; v++){
if(t + K / v <= d)
chmin(f[i][nxtj][t + K / v], f[i][j][t] + L / cal(v * 5));
}
}
}
}
int ansx = 0, ansy = 0;
for(int t = 0; t <= d; ++t){
ldb tmpt = cvt(t);
// if(tmpt <= t2)cout << tmpt << ' ' << f[xt][yt][t] << '\n';
if(tmpt - t1 >= -eps && tmpt - t2 <= eps){
if(f[xt][yt][t] != inf){
// cout << tmpt << ' ' << t << ' ' << f[xt][yt][t] << '\n';
if(!ansx || (tmpt == cvt(ansx) && f[xt][yt][t] < f[xt][yt][ansx] - eps)) ansx = t;
if(f[xt][yt][t] < f[xt][yt][ansy]) ansy = t;
}
}
}
if(!ansx) cout << "No" << '\n';
else cout << fixed << setprecision(2) << mceil(cvt(ansx)) << ' ' << f[xt][yt][ansx] << '\n' << mceil(cvt(ansy)) << ' ' << f[xt][yt][ansy];
return 0;
}
P3480 KAM-Pebbles
Staircase - Nim 的例题。
先复习一下 Nim :\(n\) 堆物品,每堆有 \(a_i\) 个,两个玩家轮流取走任意一堆的任意个物品,但不能不取。结论是,如果= \(a_1 \oplus a_2 \oplus \ldots \oplus a_n \ne 0\) 那么先手必胜,否则先手必败。证明的话 oiwiki 写得挺好的。
然后附上一个 SG 定理的新理解。对于由 \(n\) 个有向图游戏组成的组合游戏,设它们的起点分别为 \(s_1, s_2, \ldots, s_n\),则有定理:当且仅当 \(\operatorname{SG}(s_1) \oplus \operatorname{SG}(s_2) \oplus \ldots \oplus \operatorname{SG}(s_n) \neq 0\) 时,这个游戏是先手必胜的。同时,这是这一个组合游戏的游戏状态 \(x\) 的 SG 值。
首先可以发现把 \(s_i\) 移动到一个 SG 值更大的地方是没有意义的,因为总是在下一步移动会一个 SG 值等于 \(s_i\) 的地方。那么每次移动就只能让 SG 值变小,如果把 SG 值视作石子数量,就变成了 Nim 游戏。
讲回 Staircase-Nim : 有 \(n\) 堆石子,放在高度为 \(0∼n - 1\) 的阶梯上,第 \(i\) 堆有 \(a_i\) 个。每次选择一堆里 \(≥1\) 个石子放到下一级。谁不能动就输。
可以发现一个性质:如果一个人取了偶数堆上的石子移到奇数堆上,那么下一次操作总可以再把这些石子从奇数堆移动到偶数堆上,直到移动到第 0 堆无法操作,那么拿偶数堆的石子对于奇数堆就没有影响。反之,如果一个人将奇数堆的石子拿到偶数堆,对手就直接按照奇数堆 Nim 的必胜策略操作即可,相当于从奇数堆拿走了一些石子。
因此结论就显然了,只需要看奇数堆的 Nim 和是否为 0。
可以发现,本题是对于差分数组进行 Staircase-Nim。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 5;
int a[N], c[N];
void solve(){
int n; cin >> n;
for(int i = 1; i <= n; ++i)
cin >> a[i], c[i] = a[i] - a[i - 1];
int ans = 0;
for(int i = n; i >= 1; i -= 2) ans ^= c[i];
cout << (ans == 0 ? "NIE" : "TAK") << '\n';
}
int main(){
cin.tie(nullptr)->sync_with_stdio(0);
int T; cin >> T;
while(T--) solve();
return 0;
}
P2331 最大子矩阵
终于知道为啥评蓝了......
状态:dp[i][j][k]表示前i行选了j个矩阵,第i行的选的集合为k(k使用二进制)。即:当 k = 00 时,第i行没有选;当 k = 01 时,第i行选了第二个;当 k = 10 时,第i行选了第一个;当 k = 11 时,第i行两个都选了。
但是发现这个 k = 11 的状态有问题。第一列和第二列可能分属两个矩形,就不知道怎么转移了(能修但很麻烦)。
正解是 dp[i][j][k],第一列前 i 行,第二列前 j 行,划分了 k 个矩形。转移是 trival 的。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e2 + 5;
int n, m, k, f[N][N][15], a[N][2], g[N][15];
void chmax(int &a, int b){ a = max(a, b); }
int main(){
cin.tie(nullptr)->sync_with_stdio(0);
cin >> n >> m >> k;
for(int i = 1; i <= n; ++i){
for(int j = 0; j < m; ++j){
cin >> a[i][j];
}
}
memset(f, -0x3f, sizeof(f));
memset(g, -0x3f, sizeof(g));
g[0][0] = 0; f[0][0][0] = 0;
if(m == 1){
for(int i = 1; i <= n; ++i){
for(int j = 0; j <= k; ++j){
g[i][j] = g[i - 1][j];
int sum = 0;
for(int lst = i; lst; --lst){
sum += a[lst][0];
if(j != 0) chmax(g[i][j], g[lst - 1][j - 1] + sum);
}
}
}
cout << g[n][k] ;
return 0;
}
f[0][0][0] = 0;
for(int i = 0; i <= n; ++i){
for(int j = 0; j <= n; ++j){
for(int t = 0; t <= k; ++t){
chmax(f[i + 1][j][t], f[i][j][t]), chmax(f[i][j + 1][t], f[i][j][t]);
int sum = 0;
for(int nxti = i + 1; nxti <= n; ++nxti){
sum += a[nxti][0]; chmax(f[nxti][j][t + 1], f[i][j][t] + sum);
}
sum = 0;
for(int nxtj = j + 1; nxtj <= n; ++nxtj){
sum += a[nxtj][1]; chmax(f[i][nxtj][t + 1], f[i][j][t] + sum);
}
if(i == j){
sum = 0;
for(int nxt = i + 1; nxt <= n; ++nxt){
sum += a[nxt][0] + a[nxt][1];
chmax(f[nxt][nxt][t + 1], f[i][j][t] + sum);
}
}
}
}
}
int ans = -1e9;
for(int i = 0; i <= k; ++i)
chmax(ans, f[n][n][i]);
cout << ans << '\n';
return 0;
}
P2325 王室联邦
构造题。自己做出来的概率为 0...... 注意最后一个连通块因为大小不够只能并入最后的那个块。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 5;
vector<int> e[N];
int n, B, st[N], tp, bel[N], cnt, rt[N];
void dfs(int u, int fa){
int cur = tp;
for(int v : e[u]){
if(v != fa){
dfs(v, u);
if(tp - cur >= B){
++cnt;
while(tp > cur) bel[st[tp]] = cnt, tp--;
rt[cnt] = u;
}
}
}
st[++tp] = u;
}
int main(){
cin.tie(nullptr)->sync_with_stdio(0);
cin >> n >> B;
for(int i = 1; i < n; ++i){
int u, v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1, 0);
if(!cnt) ++cnt, rt[cnt] = 1;
while(tp) bel[st[tp]] = cnt, tp--;
cout << cnt << '\n';
for(int i = 1; i <= n; ++i) cout << bel[i] << ' ';
cout << '\n';
for(int i = 1; i <= cnt; ++i) cout << rt[i] << ' ';
return 0;
}
P2327 扫雷
已经退化到连黄也做不出来了是吗。实际上题目的条件很强,所以只要固定第一位,后面就都可以确定了。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 5;
typedef long long ll;
int a[N], b[N], n;
int check(){
for(int i = 2; i <= n + 1; ++i){
b[i] = a[i - 1] - b[i - 1] - b[i - 2];
if(b[i] >= 2) return 0;
if(i == n + 1 && b[i] != 0) return 0;
}
return 1;
}
int main(){
cin.tie(nullptr)->sync_with_stdio(0);
cin >> n;
for(int i = 1; i <= n; ++i) cin >> a[i];
int ans = 0;
b[1] = 1; ans += check();
b[1] = 0; ans += check();
cout << ans;
return 0;
}
P2056 捉迷藏
比较有收获的一道题。首先有一个关于树的直径的结论。若点集 \(S\) 的相距最远的两个点(称为 \(S\) 的直径)为 \(u \to v\),那么,\(S \cup \{P\}\) 的直径为 \(u \to v\), \(v \to P\), \(u \to P\) 中的一个,其中 \(P\) 是一个不存在于 \(S\) 中的点。这个还是很符合直觉的,证明也并不难。
接下来的线段树分治就是 trival 的了。可能需要提一下的是这个用 dfn 求 lca 的科技。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
vector<int> e[N], op[N * 4];
int dfn[N], st[N][20], tsp, n, dep[N];
void dfs(int u, int fa){
st[(dfn[u] = ++tsp)][0] = fa;
for(int v : e[u]){
if(v != fa) dep[v] = dep[u] + 1, dfs(v, u);
}
}
void init(){
for(int j = 1; j <= ceil(log2(n)); ++j){
for(int i = 1; i + (1 << j) - 1 <= n; ++i){
int x = st[i][j - 1], y = st[i + (1 << (j - 1))][j - 1];
st[i][j] = (dfn[x] < dfn[y] ? x : y);
}
}
}
int dist(int u, int v){
if(u == 0 || v == 0) return -1;
if(u == v) return 0;
if(dfn[v] < dfn[u]) swap(u, v);
int d = log2(dfn[v] - dfn[u]), x = st[dfn[u] + 1][d], y = st[dfn[v] - (1 << d) + 1][d];
int lca = (dfn[x] < dfn[y] ? x : y);
return dep[u] + dep[v] - 2 * dep[lca];
}
void update(int p, int pl, int pr, int L, int R, int k){
if(L <= pl && R >= pr) return void(op[p].push_back(k));
int mid = (pl + pr) >> 1;
if(L <= mid) update(p << 1, pl, mid, L, R, k);
if(R > mid) update(p << 1 | 1, mid + 1, pr, L, R, k);
}
int u, v, query[N], sta[N], lst[N];
void solve(int p, int pl, int pr){
int inu = u, inv = v;
for(int ver : op[p]){
if(!u) u = v = ver;
else{
int tmpu = u, tmpv = v;
if(dist(u, ver) > dist(tmpu, tmpv)) tmpu = u, tmpv = ver;
if(dist(v, ver) > dist(tmpu, tmpv)) tmpu = v, tmpv = ver;
u = tmpu, v = tmpv;
}
}
if(pl == pr) return query[pl] = dist(u, v), u = inu, v = inv, void();
int mid = (pl + pr) >> 1;
solve(p << 1, pl, mid), solve(p << 1 | 1, mid + 1, pr);
u = inu, v = inv;
}
int main(){
cin.tie(nullptr)->sync_with_stdio(0);
cin >> n;
for(int i = 1; i < n; ++i){
int u, v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
int q; cin >> q;
vector<int> tmp;
for(int i = 1; i <= q; ++i){
char op; cin >> op;
if(op == 'G') query[i] = 1, tmp.push_back(i);
else{
int u; cin >> u;
if(sta[u] == 0){
sta[u] = 1;
if(i != 1) update(1, 1, q, max(lst[u], 1), i - 1, u);
}
else{
sta[u] = 0;
lst[u] = i;
}
}
}
for(int i = 1; i <= n; ++i)
if(sta[i] == 0) update(1, 1, q, max(lst[i], 1), q, i);
dfs(1, 0);
init();
solve(1, 1, q);
for(int i : tmp)
cout << query[i] << '\n';
return 0;
}
P3451 ATR-Tourist Attractions
读懂题之后,最短路和状压的基本想法很符合直觉。唯一需要考虑的就是状压的转移顺序,这个稍微想一下便可以想清楚。然后就是压空间了。
Code
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int N = 2e4 + 5, K = 22;
int dist[K][N], f[2][K][200005], _sta[1 << 20], n, m, k, fl, lim[K];
vector<pii> e[N];
vector<int> sta[K];
bitset<N> done;
void dij(int s){
priority_queue<pii, vector<pii>, greater<pii> > q;
memset(dist[s], 0x3f, sizeof(dist[s]));
done.reset();
dist[s][s] = 0;
q.emplace(dist[s][s], s);
while(!q.empty()){
int d, u;
tie(d, u) = q.top();
q.pop();
if(done[u]) continue;
done[u] = 1;
for(pii t : e[u]){
int v, w; tie(v, w) = t;
if(dist[s][u] + w < dist[s][v]){
dist[s][v] = dist[s][u] + w;
q.emplace(dist[s][v], v);
}
}
}
}
void chmin(int &a, int b){ a = min(a, b); }
int main(){
cin.tie(nullptr)->sync_with_stdio(0);
cin >> n >> m >> k;
for(int i = 1; i <= m; ++i){
int u, v, w;
cin >> u >> v >> w;
e[u].emplace_back(v, w);
e[v].emplace_back(u, w);
}
for(int i = 1; i <= k + 1; ++i) dij(i);
if(k == 0) return cout << dist[1][n], 0;
for(int i = 0; i < (1 << k); ++i){
int siz = __builtin_popcount(i);
sta[siz].emplace_back(i), _sta[i] = sta[siz].size() - 1;
}
int g; cin >> g;
for(int i = 1; i <= g; ++i){
int u, v;
cin >> u >> v;
lim[v] |= (1 << (u - 2));
}
memset(f[fl], 0x3f, sizeof(f[fl]));
for(int i = 2; i <= k + 1; ++i){
if(lim[i] == 0)
f[0][i][_sta[1 << (i - 2)]] = dist[1][i];
}
for(int i = 2; i <= k; ++i){
fl ^= 1; memset(f[fl], 0x3f, sizeof(f[fl]));
for(int j = 0; j < sta[i].size(); ++j){
int t = sta[i][j];
for(int u = 2; u <= k + 1; ++u){
if((t & (1 << (u - 2))) && ((lim[u] | t) == t)){
for(int v = 2; v <= k + 1; ++v){
if(u != v && (t & (1 << (v - 2))))
chmin(f[fl][u][j], f[fl ^ 1][v][_sta[t ^ (1 << (u - 2))]] + dist[v][u]);
}
}
}
}
}
int ans = 1e9;
for(int i = 2; i <= k + 1; ++i){
chmin(ans, f[fl][i][_sta[(1 << k) - 1]] + dist[i][n]);
}
cout << ans;
return 0;
}
P3452 BIU-Offices
经典模型:求反图的连通块个数。
有 trival 的线段树优化建图做法,不过要维护联通性的话有一些细节不太一样。比如说父亲不能在一开始就向儿子连边,而应该在最后重新自上而下的遍历整棵线段树,如果发现一个非叶子节点有其他点向他连边,那么这时再向他的儿子连边。不过这个做法我没写可能还有些别的东西比较麻烦。
居然有非常优秀的 \(O(N + M)\) 做法,实际上感觉顺着往下想一下还是挺自然的。具体来说就是建一个链表,一开始将所有点加入,分为许多轮操作。每一轮开一个队列,先随便从链表里挑一个点 \(u\) 加入队列,然后扩展 \(u\) : 遍历链表,如果一个链表中的点 \(v\) 与 \(u\) 在原图上没有边(反图上有边),那么从链表中删去 \(v\),并加入队列中。扩展后将 \(u\) 弹出。一轮操作结束直到队列为空,本轮操作中加入队列的点为一个连通块。链表变为空时,程序结束。
所有点在链表中被重复遍历到且不被删去的次数是 \(O(M)\) 的,所以总的复杂度就是线性的。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
vector<int> e[N];
int n, m;
unordered_set<int> s;
bitset<N> bk;
int main(){
cin.tie(nullptr)->sync_with_stdio(0);
cin >> n >> m;
for(int i = 1; i <= m; ++i){
int u, v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
for(int i = 1; i <= n; ++i) s.insert(i);
vector<int> ans;
while(!s.empty()){
queue<int> q;
int siz = 0;
q.push(*s.begin());
s.erase(*s.begin());
while(!q.empty()){
int u = q.front(); ++siz, q.pop();
for(int v : e[u]) bk[v] = 1;
vector<int> tmp;
for(int v : s)
if(!bk[v]) tmp.push_back(v), q.push(v);
for(int v : tmp) s.erase(v);
for(int v : e[u]) bk[v] = 0;
}
ans.push_back(siz);
}
sort(ans.begin(), ans.end());
cout << ans.size() << '\n';
for(int i : ans) cout << i << ' ';
return 0;
}
P3453 DRZ-Trees
暴力分讨题。注意 \(1\) 和 \(n\) 的 corner-cases 和相邻两个点交换的情况需要特判。一个启发是离散化不一定要去重(前提是相等的两个元素满足一些性质不影响答案),这样可以在查询时方便的排除相邻的两个数的贡献。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e4 + 5;
const ll inf = 1e18;
ll x[N], val[N], _a[N], _b[N];
int a[N], b[N], h[N], n;
void chmin(ll &a, ll b){ a = min(a, b); }
ll swp(int i, int j){
if(i == j) return 0;
if(i > j) swap(i, j);
if(i == 1 && j == 2) return -abs(x[3] - x[2]) + abs(x[3] - x[1]);
if(i == n - 1 && j == n) return -abs(x[n - 1] - x[n - 2]) + abs(x[n] - x[n - 2]);
if(i + 1 == j) return -abs(x[i] - x[i - 1]) - abs(x[i + 2] - x[i + 1]) + abs(x[i + 2] - x[i]) + abs(x[i + 1] - x[i - 1]);
ll ret = 0, tmp[8] = {
-abs(x[i + 1] - x[i]),
-abs(x[i] - x[i - 1]),
-abs(x[j + 1] - x[j]),
-abs(x[j] - x[j - 1]),
abs(x[i + 1] - x[j]),
abs(x[j] - x[i - 1]),
abs(x[j + 1] - x[i]),
abs(x[i] - x[j - 1])};
for(int x = 0; x < 8; ++x) ret += tmp[x];
if(i == 1) ret -= tmp[1] + tmp[5];
if(i == n) ret -= tmp[0] + tmp[4];
if(j == 1) ret -= tmp[3] + tmp[7];
if(j == n) ret -= tmp[2] + tmp[6];
return ret;
}
struct Segment{
ll tr[N << 2];
void init(){ memset(tr, 0x3f, sizeof(tr)); }
void update(int p, int pl, int pr, int k, ll val){
if(pl == pr) return tr[p] = val, void();
int mid = (pl + pr) >> 1;
if(k <= mid) update(p << 1, pl, mid, k, val);
if(k > mid) update(p << 1 | 1, mid + 1, pr, k, val);
tr[p] = min(tr[p << 1], tr[p << 1 | 1]);
}
ll query(int p, int pl, int pr, int L, int R){
L = max(1, L), R = min(R, n);
if(L > R) return inf;
if(L <= pl && R >= pr) return tr[p];
int mid = (pl + pr) >> 1; ll ret = inf;
if(L <= mid) ret = query(p << 1, pl, mid, L, R);
if(R > mid) chmin(ret, query(p << 1 | 1, mid + 1, pr, L, R));
return ret;
}
}tr;
typedef pair<int, ll> pii;
typedef tuple<int, int, int> tpi;
vector<pii> op[N];
vector<tpi> query[N];
ll ans[N];
void prt(){
for(int i = 2; i <= n - 1; ++i)
cout << ans[i] << ' ';
cout << '\n';
}
ll qry(int pos, int l, int r){
int i = b[pos], j = a[pos];
if(j < l || i > r) return tr.query(1, 1, n, l, r);
if(j == l) return tr.query(1, 1, n, l + 1, r);
if(j < r){
if(i < l && j > l) return min(tr.query(1, 1, n, l, j - 1), tr.query(1, 1, n, j + 1, r));
if(i == l && j > l) return min(tr.query(1, 1, n, l + 1, j - 1), tr.query(1, 1, n, j + 1, r));
if(i > l) return min({tr.query(1, 1, n, l, i - 1), tr.query(1, 1, n, i + 1, j - 1), tr.query(1, 1, n, j + 1, r)});
}
if(j == r){
if(i < l) return tr.query(1, 1, n, l, r - 1);
if(i == l) return tr.query(1, 1, n, l + 1, r - 1);
if(i > l) return min(tr.query(1, 1, n, l, i - 1), tr.query(1, 1, n, i + 1, r - 1));
}
if(j > r){
if(i < l) return tr.query(1, 1, n, l, r);
if(i == l) return tr.query(1, 1, n, l + 1, r);
if(i > l && i < r) return min(tr.query(1, 1, n, l, i - 1), tr.query(1, 1, n, i + 1, r));
if(i == r) return tr.query(1, 1, n, l, r - 1);
}
}
void solve1(){
tr.init();
auto f = [](int i){ return -val[i] + _a[i] + _b[i] - 2 * x[i]; };
for(int i = 1; i <= n; ++i)
op[i].clear(), query[i].clear();
for(int i = 2; i <= n - 1; ++i)
op[1].emplace_back(h[i], f(i)), op[b[i]].emplace_back(h[i], inf);
for(int i = 2; i <= n - 1; ++i){
if(b[i] > 1)
query[h[i]].emplace_back(1, b[i] - 1, i);
}
for(int i = 1; i <= n; ++i){
for(auto [pos, val] : op[i]) tr.update(1, 1, n, pos, val);
for(auto [l, r, x] : query[i]) chmin(ans[x], qry(x, l, r) + f(x));
}
// prt();
}
void solve2(){
tr.init();
auto f = [](int i){ return _a[i] - _b[i] - val[i] - 2 * x[i]; };
auto g = [](int j){ return _a[j] + _b[j] - val[j]; };
for(int i = 1; i <= n; ++i)
op[i].clear(), query[i].clear();
for(int i = 2; i <= n - 1; ++i)
op[1].emplace_back(h[i], g(i)), op[b[i]].emplace_back(h[i], inf);
for(int i = 2; i <= n - 1; ++i)
query[h[i]].emplace_back(b[i], a[i], i);
for(int i = 1; i <= n; ++i){
for(auto [pos, val] : op[i]) tr.update(1, 1, n, pos, val);
for(auto [l, r, x] : query[i]) chmin(ans[x], qry(x, l, r) + f(x));
}
// prt();
}
void solve3(){
tr.init();
auto f = [](int i){ return -_a[i] - _b[i] - val[i] - 2 * x[i]; };
auto g = [](int j){ return _a[j] + _b[j] - val[j] + 2 * x[j]; };
for(int i = 1; i <= n; ++i)
op[i].clear(), query[i].clear();
for(int i = 2; i <= n - 1; ++i)
op[1].emplace_back(h[i], g(i)), op[b[i]].emplace_back(h[i], inf);
for(int i = 2; i <= n - 1; ++i){
if(a[i] < n)
query[h[i]].emplace_back(a[i] + 1, n, i);
}
for(int i = 1; i <= n; ++i){
for(auto [pos, val] : op[i]) tr.update(1, 1, n, pos, val);
for(auto [l, r, x] : query[i]) chmin(ans[x], qry(x, l, r) + f(x));
}
// prt();
}
void solve4(){
tr.init();
auto f = [](int i){ return _a[i] + _b[i] - val[i]; };
auto g = [](int j){ return _a[j] - _b[j] - val[j] - 2 * x[j]; };
for(int i = 1; i <= n; ++i)
op[i].clear(), query[i].clear();
for(int i = 2; i <= n - 1; ++i)
op[b[i]].emplace_back(h[i], g(i)), op[a[i] + 1].emplace_back(h[i], inf);
for(int i = 2; i <= n - 1; ++i){
if(b[i] > 1)
query[h[i]].emplace_back(1, b[i] - 1, i);
}
for(int i = 1; i <= n; ++i){
for(auto [pos, val] : op[i]) tr.update(1, 1, n, pos, val);
for(auto [l, r, x] : query[i]) chmin(ans[x], qry(x, l, r) + f(x));
}
// prt();
}
void solve5(){
tr.init();
auto f = [](int i){ return _a[i] - _b[i] - val[i]; };
for(int i = 1; i <= n; ++i)
op[i].clear(), query[i].clear();
for(int i = 2; i <= n - 1; ++i)
op[b[i]].emplace_back(h[i], f(i)), op[a[i] + 1].emplace_back(h[i], inf);
for(int i = 2; i <= n - 1; ++i)
query[h[i]].emplace_back(b[i], a[i], i);
for(int i = 1; i <= n; ++i){
for(auto [pos, val] : op[i]) tr.update(1, 1, n, pos, val);
for(auto [l, r, x] : query[i]) chmin(ans[x], qry(x, l, r) + f(x));
}
// prt();
}
void solve6(){
tr.init();
auto f = [](int i){ return -_a[i] - _b[i] - val[i]; };
auto g = [](int j){ return _a[j] - _b[j] - val[j] + 2 * x[j]; };
for(int i = 1; i <= n; ++i)
op[i].clear(), query[i].clear();
for(int i = 2; i <= n - 1; ++i)
op[b[i]].emplace_back(h[i], g(i)), op[a[i] + 1].emplace_back(h[i], inf);
for(int i = 2; i <= n - 1; ++i){
if(a[i] < n)
query[h[i]].emplace_back(a[i] + 1, n, i);
}
for(int i = 1; i <= n; ++i){
for(auto [pos, val] : op[i]) tr.update(1, 1, n, pos, val);
for(auto [l, r, x] : query[i]) chmin(ans[x], qry(x, l, r) + f(x));
}
// prt();
}
void solve7(){
tr.init();
auto f = [](int i){ return _a[i] + _b[i] - val[i] + 2 * x[i]; };
auto g = [](int j){ return -_a[j] - _b[j] - val[j] - 2 * x[j]; };
for(int i = 1; i <= n; ++i)
op[i].clear(), query[i].clear();
for(int i = 2; i <= n - 1; ++i)
op[a[i] + 1].emplace_back(h[i], g(i));
for(int i = 2; i <= n - 1; ++i){
if(b[i] > 1)
query[h[i]].emplace_back(1, b[i] - 1, i);
}
for(int i = 1; i <= n; ++i){
for(auto [pos, val] : op[i]) tr.update(1, 1, n, pos, val);
for(auto [l, r, x] : query[i]) chmin(ans[x], qry(x, l, r) + f(x));
}
// prt();
}
void solve8(){
tr.init();
auto f = [](int i){ return _a[i] - _b[i] - val[i] + 2 * x[i]; };
auto g = [](int j){ return -_a[j] - _b[j] - val[j]; };
for(int i = 1; i <= n; ++i)
op[i].clear(), query[i].clear();
for(int i = 2; i <= n - 1; ++i)
op[a[i] + 1].emplace_back(h[i], g(i));
for(int i = 2; i <= n - 1; ++i){
query[h[i]].emplace_back(b[i], a[i], i);
}
for(int i = 1; i <= n; ++i){
for(auto [pos, val] : op[i]) tr.update(1, 1, n, pos, val);
for(auto [l, r, x] : query[i]) chmin(ans[x], qry(x, l, r) + f(x));
}
// prt();
}
void solve9(){
tr.init();
auto f = [](int i){ return -_a[i] - _b[i] - val[i] + 2 * x[i]; };
for(int i = 1; i <= n; ++i)
op[i].clear(), query[i].clear();
for(int i = 2; i <= n - 1; ++i)
op[a[i] + 1].emplace_back(h[i], f(i));
for(int i = 2; i <= n - 1; ++i){
if(a[i] < n)
query[h[i]].emplace_back(a[i] + 1, n, i);
}
for(int i = 1; i <= n; ++i){
for(auto [pos, val] : op[i]) tr.update(1, 1, n, pos, val);
for(auto [l, r, x] : query[i]) chmin(ans[x], qry(x, l, r) + f(x));
}
// prt();
}
int main(){
cin.tie(nullptr)->sync_with_stdio(0);
cin >> n;
vector<int> tmp;
for(int i = 1; i <= n; ++i) cin >> x[i], tmp.push_back(i);
sort(tmp.begin(), tmp.end(), [](int i, int j){
return x[i] < x[j];
});
for(int i = 0; i < n; ++i) h[tmp[i]] = i + 1;
for(int i = 2; i <= n - 1; ++i){
_a[i] = x[i - 1], _b[i] = x[i + 1];
val[i] = abs(x[i] - x[i - 1]) + abs(x[i + 1] - x[i]);
a[i] = h[i - 1], b[i] = h[i + 1];
if(_a[i] < _b[i]) swap(_a[i], _b[i]);
if(a[i] < b[i]) swap(a[i], b[i]);
// cout << h[i] << ' ' << a[i] << ' ' << b[i] << '\n';
}
solve1(), solve2(), solve3(), solve4(), solve5(), solve6(), solve7(), solve8(), solve9();
// cout << swp(2, 3) << '\n';
for(int i : {1, n}){
for(int j = 1; j <= n; ++j)
chmin(ans[i], swp(i, j));
}
for(int i = 2; i <= n - 1; ++i){
for(int j : {1, n})
chmin(ans[i], swp(i, j));
chmin(ans[i], min(swp(i, i - 1), swp(i, i + 1)));
}
ll anstmp = 0;
for(int i = 2; i <= n; ++i) anstmp += abs(x[i] - x[i - 1]);
// cout << anstmp << '\n';
for(int i = 1; i <= n; ++i){
cout << anstmp + ans[i] << '\n';
}
return 0;
}