https://anoth3r.top/solution/nkwk116/

牛客周赛 Round 116 题解,C++ version

A 小红的区间

判断一下即可。

void solve() {
    int a, b, c, d;
    cin >> a >> b >> c >> d;
    if (a > c && b < d) cout << "A" << "\n";
    else cout << "B" << "\n";
}

B 小红的区间判断

,判断一下即可。

void solve() {
    int a, b, c, d;
    cin >> a >> b >> c >> d;
    if (a > c && b < d || a < c && b > d) cout << "A" << "\n";
    else if (b < c || a > d) cout << "B" << "\n";
    else cout << "C" << "\n";
}

C 小红的区间查询

二分左端点,查询是否在这个区间内即可,注意边界。

void solve() {
    int n, q;
    cin >> n >> q;
    vector<array<int, 3>> a(n);
    for (int i = 0; i < n; ++i) cin >> a[i][0] >> a[i][1], a[i][2] = i + 1;
    sort(all(a), [&](auto a, auto b) {
        if (a[0] != b[0]) return a[0] < b[0];
        return a[1] < b[1];
    });
 
    vector<ll> l(n);
    for (int i = 0; i < n; ++i) l[i] = a[i][0];
 
    while (q--) {
        ll x;
        cin >> x;
        int pos = upper_bound(all(l), x) - l.begin() - 1;
        if (pos >= 0) {
            auto [l, r, id] = a[pos];
            if (l <= x && x <= r) {
                cout << id << "\n";
                continue;
            }
        }
        cout << -1 << "\n";
    }
}

D 小红的区间相交

考虑反做,只需要排除存在相离的一对或存在严格包含的一对即可。

  • 相离:等价于所有区间交集为空,判断一下 的大小关系即可。

  • 严格包含:

    • 升序排序;对相同 的区间一起处理(因为 不构成严格包含)。

    • 维护到当前为止(只考虑 更小的区间)的 。对于当前组中每个区间,如果 (严格大),说明存在某个 更小且 更大的区间,发生严格包含 —— 输出

    • 组内检查完毕后再把该组的 更新到 中。

如果两个检查都通过,则输出

void solve() {
    int n, mx = -inf, mn = inf;
    cin >> n;
    vector<PII> a(n);
    for (int i = 0; i < n; ++i) {
        cin >> a[i].fi >> a[i].se;
        mx = max(mx, a[i].fi);
        mn = min(mn, a[i].se);
    }
    if (mx > mn) {
        cout << "No" << "\n";
        return;
    }
    sort(all(a), [&](auto a, auto b) {
        if (a.fi != b.fi) return a.fi < b.fi;
        return a.se < b.se;
    });
    mx = -inf;
    bool ok = false;
    int i = 0;
    while (i < n && !ok) {
        int j = i;
        while (j < n && a[j].fi == a[i].fi) ++j;
        for (int k = i; k < j; ++k) {
            if (mx > a[k].se) {
                ok = true;
                break;
            }
        }
        for (int k = i; k < j; ++k) {
            mx = max(mx, a[k].se);
        }
        i = j;
    }
    if (ok) cout << "No" << "\n";
    else cout << "Yes" << "\n";
}

E 小红的区间构造

为点 被覆盖次数。可发现相邻差分决定了每个位置需要多少区间开始或结束:

  • 结束数
  • 起始数 ​ 。

通过调节 总和使其恰为 ​ ,再用栈模拟(区间开始入栈、区间结束出栈)即可构造出合法方案。

void solve() {
    int n, m;
    ll sum = 0;
    cin >> n >> m;
    vector<ll> a(n + 2, 0);
    for (int i = 1; i <= n; i++) cin >> a[i], sum += a[i];
    a[n + 1] = 0;
 
    vector<ll> d(n + 1, 0);
    ll diff = 0;
    for (int i = 1; i <= n; i++) {
        d[i] = max(0LL, a[i] - a[i + 1]);
        diff += d[i];
    }
    if (m < diff || m > sum) {
        cout << -1 << "\n";
        return;
    }
    ll extra = m - diff;
    vector<ll> e(n + 1, 0);
    for (int i = 1; i <= n; i++) e[i] = d[i];
    for (int i = 1; i <= n && extra > 0; i++) {
        ll cap = a[i] - e[i];
        if (cap <= 0) continue;
        ll use = min(cap, extra);
        e[i] += use;
        extra -= use;
    }
    vector<ll> s(n + 1, 0);
    s[1] = a[1];
    for (int i = 2; i <= n; i++) {
        s[i] = (a[i] - a[i - 1]) + e[i - 1];
        if (s[i] < 0) {
            cout << -1 << "\n";
            return;
        }
    }
    ll S = 0;
    for (int i = 1; i <= n; i++) S += s[i];
    if (S != m) {
        cout << -1 << "\n";
        return;
    }
 
 
    vector<PII> ans;
    vector<int> stk;
    for (int i = 1; i <= n; i++) {
        for (ll t = 0; t < s[i]; ++t) stk.pb(i);
        for (ll t = 0; t < e[i]; ++t) {
            if (stk.empty()) {
                cout << -1 << "\n";
                return;
            }
            int l = stk.back(); stk.pop_back();
            ans.eb(l, i);
        }
    }
    if (ans.size() != m) {
        cout << -1 << "\n";
        return;
    }
    for (auto [u, v] : ans) cout << u << " " << v << "\n";
}

F 小红的区间创建

每个已有区间把区间轴划分为若干相交与非相交段。 对每个位置

  • 为覆盖到 的区间最小右端点;新区间若包含 ,其右端点需
  • 为覆盖到 的区间最大左端点;若包含 ,其左端点需

再排除已有区间端点,统计所有满足左右限制的不相交区间对数即可。

void solve() {
    int n, m;
    cin >> n >> m;
    vector<PII> a(n);
    for (int i = 0; i < n; ++i) cin >> a[i].fi >> a[i].se;

    vector<vector<int>> mna(m + 3), mnr(m + 3);
    for (auto [l, r] : a) {
        if (l + 1 <= m) mna[l + 1].pb(r);
        if (r + 1 <= m) mnr[r + 1].pb(r);
    }
    multiset<int> ms;
    vector<int> mr(m + 1, m + 1);
    for (int x = 1; x <= m; x++) {
        for (int v : mna[x]) ms.insert(v);
        for (int v : mnr[x]) {
            auto it = ms.find(v);
            if (it != ms.end()) ms.erase(it);
        }
        if (ms.empty()) mr[x] = m + 1;
        else mr[x] = *ms.begin();
    }


    vector<vector<int>> mxa(m + 2), mxr(m + 2);
    for (auto [l, r] : a) {
        mxa[l].pb(l);
        if (r <= m) mxr[r].pb(l);
    }
    multiset<int> ms2;
    vector<int> ml(m + 1, 0);
    for (int x = 1; x <= m; x++) {
        for (int v : mxa[x]) ms2.insert(v);
        for (int v : mxr[x]) {
            auto it = ms2.find(v);
            if (it != ms2.end()) ms2.erase(it);
        }
        if (ms2.empty()) ml[x] = 0;
        else ml[x] = *ms2.rbegin();
    }

    vector<bool> vis(m + 2, 0);
    for (auto [l, r] : a) {
        vis[l] = 1;
        vis[r] = 1;
    }

    vector<vector<int>> bucket(m + 3);
    for (int i = 1; i <= m; i++) {
        int T = ml[i] + 1;
        if (T < 1) T = 1;
        if (T > m + 1) T = m + 1;
        if (i >= 1 && i <= m) bucket[T <= m + 1 ? T : m + 1].pb(i);
    }

    BIT<int> bit(m);
    ll ans = 0;
    for (int i = 1; i <= m; ++i) {
        for (int j : bucket[i]) {
            if (!vis[j]) bit.add(j, 1);
        }
        if (vis[i]) continue;
        int mx = (mr[i] == m + 1 ? m : mr[i] - 1);
        if (mx < i) continue;
        ans += bit.ask(i, mx);
    }
    cout << ans << "\n";
}

头文件

//Another
#include<bits/stdc++.h>
#include<bits/extc++.h>
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()
using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef __int128 i128;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
typedef tuple<ll, ll, ll> TLLL;
typedef __gnu_pbds::tree<PLL, __gnu_pbds::null_type, less<PLL>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update> Tree;
// typedef __gnu_pbds::tree<ll, __gnu_pbds::null_type, less<ll>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update> Tree;

constexpr int inf = (ll)1e9 + 7;
constexpr ll INF = (ll)2e18 + 9;
// constexpr ll INF = (ll)4e18;
// constexpr ll MOD = 1e9 + 7;
constexpr ll MOD = 998244353;
constexpr ld PI = acos(-1.0);
constexpr ld eps = 1e-10;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ull randint(ull l, ull r) {uniform_int_distribution<unsigned long long> dist(l, r); return dist(rng);}

void init() {

}

void solve() {
    
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);

    init();

    int t = 1;
    cin >> t;
    for (int _ = 1; _ <= t; ++_) {
        solve();
    }
    return 0;
}

树状数组

template<class Int>
struct BIT {
    vector<Int> a;
    int n;

    BIT() {}
    BIT(int n) {
        init(n);
    }

    void init(int n) {
        this->n = n;
        a.resize(n + 1);
    }

    void add(int x, int k) {
        for (; x <= n; x += x & -x) {
            a[x] += k;
        }
    }

    void add(int x, int y, Int k) {
        add(x, k), add(y + 1, -k);
    }

    Int ask(int x) {
        Int ans = 0;
        for (; x; x -= x & -x) {
            ans += a[x];
        }
        return ans;
    }

    Int ask(int x, int y) {
        return ask(y) - ask(x - 1);
    }

    Int kth(int k) {
        Int ans = 0;
        for (int i = __lg(n); i >= 0; i--) {
            Int val = ans + (1 << i);
            if (val < n && a[val] < k) {
                k -= a[val];
                ans = val;
            }
        }
        return ans + 1;
    }
};