其他分享
首页 > 其他分享> > CF1685E The Ultimate LIS Problem【构造,线段树】

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

作者:互联网

传送门

思路

考虑如何判无解,也就是说所有循环移位的 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。

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

对于条件 \(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