CF1718D Permutation for Burenka【贪心】

传送门


显然,两个数列相似当且仅当它们的笛卡尔树结构相同。

那么排列 \(p\) 给出了 \(a\) 所对应的笛卡尔树形态,据此我们容易求出树上每个空位上数的取值范围 \([l_i,r_i]\)。当然如果已经填的数不合法那么一定无解,这个可以先判掉。

然后我们会发现这个也是充分的,因为如果两个位置都满足限制但是不符合笛卡尔树结构,那么它们肯定在同一个由空位组成的连通块内,瞎交换一下总能达到合法。由此我们可以得到判定 \(T = S \cup \{d\}\) 合法的充要条件:存在一组将 \(T\) 中所有元素 \(v\) 和所有区间 \([l_i,r_i]\) 两两匹配的方案,使得 \(v \in [l_p,r_p]\)\(p\)\(v\) 所匹配的区间)。

对确定的 \(T\),我们有如下贪心的判定方法:每次选择最小的未被匹配的 \(v\),将其与右端点最小的、包含 \(v\) 且未被匹配的区间匹配。其正确性显然。这等价于将所有区间按 \(r\) 从小到大排序,每次选择 \([l_i, r_i]\) 中最小的未被匹配的 \(v\) 并删去。若不存在这样的 \(v\) 则无解,我们称这个区间为不合法区间。

考虑对 \(S\) 做上述贪心,这时候肯定至少有一个区间不合法,我们先把它抓出来。设这个区间为 \([l_i,r_i]\),那么显然应该有 \(d \leq r_i\),这时候我们就得到了合法的 \(d\) 的一个取值上界。然后我们假装这个区间已经被匹配了并继续贪心,如果又找到了一个不合法区间,那么肯定就没救了。证明比较容易,这里就不写了。

同理,倒过来贪一遍可以得到 \(d\) 的取值下界,由此可知 \(d\) 的取值范围 \([L,R]\)。事实上这是充分的:

原问题是二分图完备匹配的形式,我们尝试使用 Hall 定理描述其有解性。对于这类点向区间连边的匹配问题,一个经典结论是存在完备匹配当且仅当完全包含于 \([l,r]\) 的区间数量不大于 \([l,r]\) 中的元素数量。

因为这个太经典了所以这里就不证了。算了还是简单证一下好了,我们考虑右部选的点集 \(S\),它是一些不交区间的并,进一步我们可以发现这些不交区间在左部的点集也是独立的,然后就只需要考虑一个子区间的情况了。

\(c_{l,r}\) 为完全包含于 \([l,r]\) 的区间数量,\(f_{l,r} = c_{l,r} - \sum_{v \in T}[l \leq v \land v \leq r]\)。显然如果存在 \(f_{l,r} > 1\) 那又没救了。

考虑 \(f_{l,r} = 1\) 的区间 \([l,r]\),完全包含于 \([l,r]\) 的区间中至少有一个没得匹配,所以贪心过程中枚举到 \(r\) 时必然会找到这个不合法区间,因此有 \(R \leq r\)。同理可证 \(L \geq l\)。因此往 \([L,R]\) 中塞一个点后所有 \(f_{l,r} = 1\) 的区间全都变成 \(0\) 了,即充分性得证。

于是只需要求出 \([L,R]\) 即可。用 set 维护贪心过程,时间复杂度 \(O(n \log n + q)\)

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) memset(x, v, sizeof(x))
#define mcpy(x, y, n) memcpy(x, y, sizeof(int) * (n))
#define lob lower_bound
#define upb upper_bound
#define TIME 1e3 * clock() / CLOCKS_PER_SEC
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;
}

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

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

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, Q, K, fl, p[MN], a[MN], d[MN];
int stk[MN], tp, ls[MN], rs[MN], f[MN];
vector <pii> vr;

inline void dfs1(int u) {
    if (!u) return;
    dfs1(ls[u]), dfs1(rs[u]);
    if (a[u]) f[u] = a[u] + 1;
    else f[u] = max(1, max(f[ls[u]], f[rs[u]]));
}
inline void dfs2(int u, int rb) {
    if (!u) return;
    if (!a[u]) vr.pb(mp(f[u], rb));
    else fl |= f[u] > rb, rb = a[u] - 1;
    dfs2(ls[u], rb), dfs2(rs[u], rb);
}
inline void work() {
    N = read(), Q = read();
    for (int i = 1; i <= N; i++) 
        p[i] = read(), ls[i] = rs[i] = 0;
    tp = 0;
    for (int i = 1; i <= N; i++) {
        while (tp && p[stk[tp]] < p[i]) ls[i] = stk[tp--];
        rs[stk[tp]] = i;
        stk[++tp] = i;
    }
    ls[0] = rs[0] = fl = 0;
    K = 0, vr.clear();
    for (int i = 1; i <= N; i++)
        a[i] = read(), K += !a[i];
    dfs1(stk[1]);
    dfs2(stk[1], inf);
    set <int> s;
    for (int i = 1; i < K; i++) 
        d[i] = read(), s.insert(d[i]);
    int L = 0, R = inf;
    auto cmp1 = [&](pii x, pii y) { 
        return x.fi > y.fi; 
    };
    sort(vr.begin(), vr.end(), cmp1);
    for (auto it : vr) {
        int l = it.fi, r = it.se;
        auto p = s.upb(r);
        if (p == s.begin() || *--p < l) {
            if (L) { fl = 1; break; }
            L = l;
        } else {
            s.erase(p);
        }
    } 
    auto cmp2 = [&](pii x, pii y) { 
        return x.se < y.se; 
    };
    sort(vr.begin(), vr.end(), cmp2);
    s.clear();
    for (int i = 1; i < K; i++) s.insert(d[i]);
    for (auto it : vr) {
        int l = it.fi, r = it.se;
        auto p = s.lob(l);
        if (p == s.end() || *p > r) {
            if (R < inf) { fl = 1; break; }
            R = r;
        } else {
            s.erase(p);
        }
    }
    while (Q--) {
        int x = read();
        puts(!fl && L <= x && x <= R ? "YES" : "NO");
    }
}

signed main(void) {
    int T = read();
    while (T--) work();
    return 0;
}
posted @ 2022-09-21 20:03  came11ia  阅读(39)  评论(0编辑  收藏  举报