ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1685E The Ultimate LIS Problem【构造,线段树】

2022-07-20 13:33:45  阅读:163  来源: 互联网

标签:int void pos CF1685E Ultimate LIS 移位 define


传送门

思路

考虑如何判无解,也就是说所有循环移位的 LIS 长度均大于 \(n\)。

一个括号序列的结论突然出现:令 \(b_i = [p_i > n+1] - [p_i<n+1]\),那么 \(b\) 中恰好包含 \(n\) 个 \(1\),\(n\) 个 \(1\) 和 \(1\) 个 \(0\)。根据 Raney 引理的推论,其存在一个循环移位满足所有前缀和均 \(\geq 0\)。接下来我们证明在这个循环移位中,如果 LIS 的长度 \(> n\),那么 \(n+1\) 一定在 LIS 中。

考虑反证,如果 \(n+1\) 不在 LIS 中,那么 LIS 由前面的 \(x\) 个 \(-1\) 接上至少 \(n-x+1\) 个 \(1\) 组成。由于 \(1\) 和 \(-1\) 都恰有 \(n\) 个,所以第 \(x\) 个 \(1\) 一定在第 \(x\) 个 \(-1\) 之后出现,这与所有前缀和均 \(\geq 0\) 矛盾。所以这个 LIS 一定为 \(x\) 个 \(-1\) 接上 \(0\) 再接上至少 \(n-x\) 个 \(-1\),又由所有前缀和 \(\geq 0\) 可以推出 \(0\) 之前 \(1,-1\) 都恰有 \(x\) 个,\(0\) 之后 \(1,-1\) 都恰有 \(n-x\) 个。

这启发我们观察 \(n+1\) 在开头和结尾的循环移位的 LIS,容易发现这两个循环移位仍然满足所有前缀和均 \(\geq 0\),所以 LIS 必定包含 \(n+1\),从而两个 LIS 分别为 \(n+1,n+2,\cdots,2n+1\) 和 \(1,2,\cdots,n+1\)。考虑其逆否命题,我们还可以得出若 \(n+1\) 在开头的循环移位不满足所有前缀和均 \(\geq n\),那么其所有前缀和均 \(\geq n\) 的循环移位的 LIS 一定 \(\leq n\)。

事实上,我们可以证明,只要 \(n+1\) 在开头和结尾的循环移位的 LIS 均 \(> n\) 就一定无解。因为 \(n+1\) 在最前面的循环移位满足 \(b\) 的所有前缀和均 \(\geq 0\),且 \(b\) 的总和为 \(0\),那么 \(b\) 的所有后缀和均 \(\leq 0\)。进一步我们可以得到,任何一个循环移位在 \(0\) 之前的 \(-1\) 的个数一定不小于 \(1\) 的个数。此时只要选取 \(0\) 之前所有的 \(-1\),\(0\),以及 \(0\) 之后所有的 \(1\) 就得到了一个长度 \(> n\) 的 LIS。

综上,我们得到了这样的求解方法:

  • 找到 \(n+1\) 在开头的循环移位,若有前缀和 \(<0\),找到一个所有前缀和均 \(\geq 0\) 的循环移位即可。

  • 判断 \(n+1\) 在结尾的循环移位中 \(1,2,\cdots,n+1\) 是否从左往右依次出现,如果不是,则解即为此循环移位。

  • 判断 \(n+1\) 在开头的循环移位中 \(n+1,n+2,\cdots,2n+1\) 是否从左往右依次出现,如果不是,则解即为此循环移位。

  • 否则无解。

对于条件 \(1\),维护 \(b\) 的前缀和即前缀和的最小值容易判断。对于条件 \(2\),可以维护

\[\mathrm{s1} = \sum_{i=1}^n (\mathrm{pos}_{i+1} - \mathrm{pos}_i) \bmod (2n+1) + (\mathrm{pos}_1 - \mathrm{pos}_{n+1}) \bmod (2n+1) \]

判断 \(\mathrm{s1} = 2n+1\) 是否成立即可,条件 \(3\) 的判断与条件 \(2\) 类似。时间复杂度 \(O(n \log n)\)。

Code
/*
也许所有的执念 就像四季的更迭
没有因缘 不需致歉
是否拥抱着告别 就更能读懂人间
还是感慨 更多一点
*/
#include <bits/stdc++.h>
#define pii pair<int, int>
#define mp(x, y) make_pair(x, y)
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define int long long
#define mem(x, v, n) memset(x, v, sizeof(int) * (n))
#define mcpy(x, y, n) memcpy(x, y, sizeof(int) * (n))
#define lob lower_bound
#define upb upper_bound
using namespace std;

inline int read() {
	int x = 0, w = 1;char ch = getchar();
	while (ch > '9' || ch < '0') { if (ch == '-')w = -1;ch = getchar(); }
	while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
	return x * w;
}

inline int min(int x, int y) { return x < y ? x : y; }
inline int max(int x, int y) { return x > y ? x : y; }

const int MN = 2e5 + 5;
const int Mod = 1e9 + 7;

inline void Pls(int &x, int y) { x += y; if (x >= Mod) x -= Mod; }
inline void Dec(int &x, int y) { x -= y; if (x < 0) x += Mod; }

inline int qPow(int a, int b = Mod - 2, int ret = 1) {
    while (b) {
        if (b & 1) ret = ret * a % Mod;
        a = a * a % Mod, b >>= 1;
    }
    return ret;
}

// #define dbg

int N, M, a[MN], s[MN], pos[MN], s1, s2;

#define f(x, y) (x < y ? y - x : N * 2 - x + y + 1)

const int MS = MN << 2;
#define ls o << 1
#define rs o << 1 | 1
#define mid ((l + r) >> 1)
#define LS ls, l, mid
#define RS rs, mid + 1, r
int val[MS], tag[MS];
inline void upd(int o, int v) { val[o] += v, tag[o] += v; }
inline void Pushup(int o) { val[o] = min(val[ls], val[rs]); }
inline void Pushdown(int o) {
    upd(ls, tag[o]), upd(rs, tag[o]), tag[o] = 0;
}
inline void Build(int o, int l, int r) {
    if (l == r) return val[o] = s[l], void();
    Build(LS), Build(RS), Pushup(o);
}   
inline void Mdf(int o, int l, int r, int L, int R, int v) {
    if (r < L || l > R) return;
    if (L <= l && R >= r) return upd(o, v), void();
    Pushdown(o), Mdf(LS, L, R, v), Mdf(RS, L, R, v), Pushup(o);
}
inline int Qval(int o, int l, int r, int p) {
    if (l == r) return val[o];
    return Pushdown(o), (p <= mid ? Qval(LS, p) : Qval(RS, p));
}
inline int Qry(int o, int l, int r) {
    if (l == r) return l;
    return Pushdown(o), (val[o] == val[ls] ? Qry(LS) : Qry(RS));
}
#undef mid

inline void Upd(int x, int y) {
    if (x < N + 1) {
        Mdf(1, 0, N * 2 + 1, pos[x], N * 2 + 1, 1);
        s1 -= f(pos[x > 1 ? x - 1 : N + 1], pos[x]) + f(pos[x], pos[x + 1]);
        pos[x] = y;
        Mdf(1, 0, N * 2 + 1, pos[x], N * 2 + 1, -1);
        s1 += f(pos[x > 1 ? x - 1 : N + 1], pos[x]) + f(pos[x], pos[x + 1]);
    } else if (x > N + 1) {
        Mdf(1, 0, N * 2 + 1, pos[x], N * 2 + 1, -1);
        s2 -= f(pos[x - 1], pos[x]) + f(pos[x], pos[x <= N * 2 ? x + 1 : N + 1]);
        pos[x] = y;
        Mdf(1, 0, N * 2 + 1, pos[x], N * 2 + 1, 1);
        s2 += f(pos[x - 1], pos[x]) + f(pos[x], pos[x <= N * 2 ? x + 1 : N + 1]);
    } else {
        s1 -= f(pos[N], pos[x]) + f(pos[x], pos[1]);
        s2 -= f(pos[N * 2 + 1], pos[x]) + f(pos[x], pos[N + 2]);
        pos[x] = y;
        s1 += f(pos[N], pos[x]) + f(pos[x], pos[1]);
        s2 += f(pos[N * 2 + 1], pos[x]) + f(pos[x], pos[N + 2]);
    }
}
inline void Solve() {
    if (Qval(1, 0, N * 2 + 1, pos[N + 1]) != val[1]) return printf("%lld\n", Qry(1, 0, N * 2 + 1)), void();
    if (s1 > N * 2 + 1) return printf("%lld\n", pos[N + 1] <= N * 2 ? pos[N + 1] : 0), void();
    if (s2 > N * 2 + 1) return printf("%lld\n", pos[N + 1] - 1), void();
    puts("-1");
}

signed main(void) {
    N = read(), M = read();
    for (int i = 1; i <= N * 2 + 1; i++) a[i] = read();
    for (int i = 1; i <= N * 2 + 1; i++) s[i] = s[i - 1] + (a[i] > N + 1) - (a[i] <= N);
    Build(1, 0, N * 2 + 1);
    for (int i = 1; i <= N * 2 + 1; i++) pos[a[i]] = i;
    s1 = f(pos[N + 1], pos[1]), s2 = f(pos[N * 2 + 1], pos[N + 1]);
    for (int i = 1; i <= N; i++) s1 += f(pos[i], pos[i + 1]);
    for (int i = N + 1; i <= 2 * N; i++) s2 += f(pos[i], pos[i + 1]);
    while (M--) {
        int x = read(), y = read();
        Upd(a[x], y);
        Upd(a[y], x);
        swap(a[x], a[y]);
        Solve();
    }
    return 0;
}

标签:int,void,pos,CF1685E,Ultimate,LIS,移位,define
来源: https://www.cnblogs.com/came11ia/p/16497616.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有