ABC 283 F - Permutation Distance(推公式,维护二维偏序)

F - Permutation Distance

题意

​ 给出一个排列 P。求序列D,Di的定义如下。

Di=minji{|PiPj|+|ij|}

思路

​ 在题目中遇到绝对值问题时,我们应该通过分类讨论来去掉绝对值,所以上式可以被拆成四个式子,如下:

1.Di=(iPi)+min{Pjj}(Pi<Pj && i>j)

2.Di=(iPi)+min{Pj+j}(Pi<Pj && i<j)

3.Di=(Pi+i)+min{Pjj}(Pi>Pj && i>j)

4.Di=(Pii)+min{Pj+j}(Pi>Pj && i<j)

​ 得到这个式子之后,那就是一个很裸的二维偏序维护问题。所以我们需要一共遍历四遍,用4个线段树来维护每个式子来更新答案。

​ 对于 i>j,需要正序维护;反之倒序维护。

代码

#include <bits/stdc++.h>

using namespace std;
const int N = 200005;
int n;
int res[N], p[N];

struct SegmentTree{
    struct Tree{
        int l, r;
        int mn;
    }tr[N * 4];
    void pushup(int u)
    {
        tr[u].mn = min(tr[u<<1].mn, tr[u<<1|1].mn);
    }
    void build(int u, int l, int r)
    {
        tr[u] = {l, r};
        if (l == r)
            tr[u].mn = 1e9;
        else 
        {
            int mid = (l + r) >> 1;
            build(u<<1, l, mid);
            build(u<<1|1, mid + 1, r);
            pushup(u);
        }
    }
    void update(int u, int x, int t)
    {// 单点修改,不需要懒标记
        int l = tr[u].l, r = tr[u].r, mid = (l + r) >> 1;
        if (l == r)
        {
            tr[u].mn = min(tr[u].mn, t);
        }
        else 
        {
            if (x <= mid) update(u<<1, x, t);
            else update(u<<1|1, x, t);
            pushup(u);
        }
    }   
    int query(int u, int x, int y)
    {// 查询区间[x, y]的最值
        int l = tr[u].l, r = tr[u].r, mid = (l + r) >> 1;
        if (x <= l && y >= r) return tr[u].mn;
        else
        {
            int ans = 1e9;
            if (x <= mid) ans = min(ans, query(u<<1, x, y));
            if (y > mid) ans = min(ans, query(u<<1|1, x, y));
            return ans;
        }
    }
}T1, T2;

int main()
{
	cin >> n;
	for(int i = 1; i <= n; i ++)
		cin >> p[i];
	memset(res, 0x3f, sizeof res);

	T1.build(1, 1, n);
	T2.build(1, 1, n);
	for(int i = 1; i <= n; i ++)
	{
		res[i] = min(res[i], p[i] + i + T1.query(1, 1, p[i]));
		res[i] = min(res[i], -p[i] + i + T2.query(1, p[i], n));
		T1.update(1, p[i], -p[i] - i);
		T2.update(1, p[i], p[i] - i);
	}

	T1.build(1, 1, n);
	T2.build(1, 1, n);
	for(int i = n; i >= 1; i --)
	{
		res[i] = min(res[i], p[i] - i + T1.query(1, 1, p[i]));
		res[i] = min(res[i], -p[i] - i + T2.query(1, p[i], n));
		T1.update(1, p[i], -p[i] + i);
		T2.update(1, p[i], p[i] + i);
	}

	for(int i = 1; i <= n; i ++)
		cout << res[i] << ' ';
	cout << '\n';
}
posted @   DM11  阅读(86)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示
主题色彩