• Solution 「WC 2022」秃子酋长


    \(\mathscr{Description}\)

      Link. (It's empty temporarily.)

      给定排列 \(\{a_n\}\)\(q\) 次询问,每次给出 \([l,r]\),求升序枚举 \(a_{l..r}\) 时下标的移动距离。

      \(n,q\le5\times10^5\)

    \(\mathscr{Solution}\)

      我写了个不加莫队,它慢死了。

      我写了个 Ynoi 风格的纯纯分块预处理,它慢死了。

      我写了个 polylog 的正解,它还是慢死了。


      喵树分治,每次处理跨过区间中点的询问。左右区间互相的影响形式形如:“若右区间包含一个 \([x,y]\) 内的数,则答案变化量为 \(\Delta\)。”注意左右区间包含了哪些数仅跟一个端点有关,所以类似于区间数点的形式,可以考虑离线维护。

      以计算左区间产生的 \(\Delta\) 为例。枚举左区间端点 \(p=\textit{mid}..l\),用 std::set 之类的东西暴力维护左区间前驱后继。现在加入 \(a_p\),设其前驱为 \(x\),后继为 \(y\),内部贡献先计算;对于跨区间影响,我们得到了两个新的“连续键” \(x\rightarrow a_p\) 以及 \(a_p\rightarrow y\),去掉了一个旧的“连续键” \(x\rightarrow y\),而我们可以分别找到右区间第一个能“断键”的数的位置 \(k\),把对应的变化量挂在 \(k\) 位置。然后枚举左端点为 \(p\) 的询问,将询问对应的右端点及其左侧的所有“断键”变化量都计入询问答案。右区间也做类似的事情即可。

      复杂度是 \(\mathcal O(n\log^2 n)\),隐约记得 lxl 说有基于并查集的低于这一复杂度的做法?

    \(\mathscr{Code}\)

      那个线段树可以替换成离线啊,怪不得那么慢 qwq。

    /*+Rainybunny+*/
    
    #include <bits/stdc++.h>
    
    #define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
    #define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i)
    
    typedef long long LL;
    typedef std::pair<int, int> PII;
    #define fi first
    #define se second
    
    inline char fgc() {
        static char buf[1 << 17], *p = buf, *q = buf;
        return p == q && (q = buf + fread(p = buf, 1, 1 << 17, stdin), p == q) ?
          EOF : *p++;
    }
    
    template <typename Tp = int>
    inline Tp rint() {
        Tp x = 0, s = fgc(), f = 1;
        for (; s < '0' || '9' < s; s = fgc()) f = s == '-' ? -f : f;
        for (; '0' <= s && s <= '9'; s = fgc()) x = x * 10 + (s ^ '0');
        return x * f;
    }
    
    template <typename Tp>
    inline void wint(Tp x) {
        if (x < 0) putchar('-'), x = -x;
        if (9 < x) wint(x / 10);
        putchar(x % 10 ^ '0');
    }
    
    inline int iabs(const int u) { return u < 0 ? -u : u; }
    template <typename Tp>
    inline void chkmin(Tp& u, const Tp& v) { v < u && (u = v, 0); }
    template <typename Tp>
    inline void chkmax(Tp& u, const Tp& v) { u < v && (u = v, 0); }
    template <typename Tp>
    inline Tp imin(const Tp& u, const Tp& v) { return u < v ? u : v; }
    template <typename Tp>
    inline Tp imax(const Tp& u, const Tp& v) { return u < v ? v : u; }
    
    const int MAXN = 5e5, IINF = 0x3f3f3f3f;
    int n, q, a[MAXN + 5], ref[MAXN + 5];
    LL ans[MAXN + 5];
    struct Query { int l, r, id; };
    std::vector<Query> ask[MAXN * 2 + 5];
    
    struct SegmentTree {
        int mn[MAXN << 2], mx[MAXN << 2];
        
        inline void build(const int u, const int l, const int r) {
            mn[u] = IINF, mx[u] = -1;
            if (l == r) return ;
            int mid = l + r >> 1;
            build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
        }
    
        inline void modify(const int u, const int l, const int r,
          const int x, const int v) {
            if (l == r) {
                if (v) mn[u] = mx[u] =  v;
                else mn[u] = IINF, mx[u] = -1;
                return ;
            }
            int mid = l + r >> 1;
            if (x <= mid) modify(u << 1, l, mid, x, v);
            else modify(u << 1 | 1, mid + 1, r, x, v);
            mn[u] = imin(mn[u << 1], mn[u << 1 | 1]);
            mx[u] = imax(mx[u << 1], mx[u << 1 | 1]);
        }
    
        inline int qmin(const int u, const int l, const int r,
          const int ql, const int qr) {
            if (ql <= l && r <= qr) return mn[u];
            int mid = l + r >> 1, ret = IINF;
            if (ql <= mid) chkmin(ret, qmin(u << 1, l, mid, ql, qr));
            if (mid < qr) chkmin(ret, qmin(u << 1 | 1, mid + 1, r, ql, qr));
            return ret;
        }
    
        inline int qmax(const int u, const int l, const int r,
          const int ql, const int qr) {
            if (ql <= l && r <= qr) return mx[u];
            int mid = l + r >> 1, ret = -1;
            if (ql <= mid) chkmax(ret, qmax(u << 1, l, mid, ql, qr));
            if (mid < qr) chkmax(ret, qmax(u << 1 | 1, mid + 1, r, ql, qr));
            return ret;
        }
    } sgt;
    
    struct BIT {
        LL val[MAXN + 5];
        bool rec[MAXN + 5]; int stk[MAXN + 5];
    
        inline void add(int x, const int v) {
            for (; x <= n; x += x & -x) {
                val[x] += v, !rec[x] && (rec[stk[++stk[0]] = x] = true);
            }
        }
    
        inline LL sum(int x) {
            LL ret = 0;
            for (; x; x -= x & -x) ret += val[x];
            return ret;
        }
    
        inline void restore() {
            for (int& top = stk[0]; top; --top) {
                rec[stk[top]] = false, val[stk[top]] = 0;
            }
        }
    } bit;
    
    #define TID(l, r) (l + r | (l != r))
    
    inline void hang(const int l, const int r, const Query& qr) {
        int mid = l + r >> 1;
        if (qr.l <= mid && mid < qr.r) return ask[TID(l, r)].push_back(qr);
        if (qr.r <= mid) hang(l, mid, qr);
        else hang(mid + 1, r, qr);
    }
    
    inline void solve(const int l, const int r) {
        if (l == r) return ;
        int mid = l + r >> 1; auto& qvec(ask[TID(l, r)]);
        solve(l, mid), solve(mid + 1, r);
        if (qvec.empty()) return ;
    
        LL curs = 0; static std::set<int> st;
        auto insert = [&](const int x)->PII {
            auto&& it(st.insert(x).first); int p = 0, q = 0;
            if (std::next(it) != st.end()) q = *std::next(it);
            if (it != st.begin()) p = *std::prev(it);
            if (p) curs += iabs(ref[x] - ref[p]);
            if (q) curs += iabs(ref[x] - ref[q]);
            if (p && q) curs -= iabs(ref[p] - ref[q]);
            return { p, q ? q : n + 1 };
        };
    
        auto bondL = [&](const int x, const int y, const int op)->void {
            if (x + 1 == y) return ;
            int k = sgt.qmin(1, 1, n, x + 1, y - 1);
            if (!(1 <= k && k <= n)) return ;
            int dlt = (1 <= x ? -ref[x] : 0) + (y <= n ? -ref[y] : 0)
              + (1 <= x && y <= n ? -iabs(ref[x] - ref[y]) : 0);
            bit.add(k, op * dlt);
        };
        bit.restore(), st.clear(), curs = 0;
        rep (i, mid + 1, r) sgt.modify(1, 1, n, a[i], i);
        std::sort(qvec.begin(), qvec.end(),
          [](const Query& u, const Query& v) { return u.l > v.l; });
        for (int i = mid, j = 0; i >= l && j != qvec.size(); --i) {
            PII p = insert(a[i]);
            bondL(p.fi, a[i], 1), bondL(a[i], p.se, 1), bondL(p.fi, p.se, -1);
            for (; j != qvec.size() && qvec[j].l == i; ++j) {
                ans[qvec[j].id] += curs + bit.sum(qvec[j].r);
            }
        }
        rep (i, mid + 1, r) sgt.modify(1, 1, n, a[i], 0);
    
        auto bondR = [&](const int x, const int y, const int op)->void {
            if (x + 1 == y) return ;
            int k = sgt.qmax(1, 1, n, x + 1, y - 1);
            if (!(1 <= k && k <= n)) return ;
            int dlt = (1 <= x ? ref[x] : 0) + (y <= n ? ref[y] : 0)
              + (1 <= x && y <= n ? -iabs(ref[x] - ref[y]) : 0);
            bit.add(n - k + 1, op * dlt);
        };
        bit.restore(), st.clear(), curs = 0;
        rep (i, l, mid) sgt.modify(1, 1, n, a[i], i);
        std::sort(qvec.begin(), qvec.end(),
          [](const Query& u, const Query& v) { return u.r < v.r; });
        for (int i = mid + 1, j = 0; i <= r && j != qvec.size(); ++i) {
            PII p = insert(a[i]);
            bondR(p.fi, a[i], 1), bondR(a[i], p.se, 1), bondR(p.fi, p.se, -1);
            for (; j != qvec.size() && qvec[j].r == i; ++j) {
                ans[qvec[j].id] += curs + bit.sum(n - qvec[j].l + 1);
            }
        }
        rep (i, l, mid) sgt.modify(1, 1, n, a[i], 0);
    }
    
    int main() {
        n = rint(), q = rint();
        rep (i, 1, n) ref[a[i] = rint()] = i;
        rep (i, 1, q) {
            int l = rint(), r = rint();
            if (l != r) hang(1, n, { l, r, i });
        }
    
        sgt.build(1, 1, n), solve(1, n);
        rep (i, 1, q) wint(ans[i]), putchar('\n');
        return 0;
    }
    
    
  • 相关阅读:
    多线程(5)async&await
    多线程(4)Task
    多线程(3)ThreadPool
    多线程(2)Thread
    多线程(1)认识多线程
    泛型
    反射(4)反射性能问题:直接调用vs反射调用
    反射(3)反射应用:一个插件项目
    反射(2)使用反射
    反射(1)认识反射
  • 原文地址:https://www.cnblogs.com/rainybunny/p/15851882.html
Copyright © 2020-2023  润新知