模板及例题

===

Index

algorithm

并行二分

第k大数

给定n个初始为空的数组t1,…tn, 首先执行m次元素插入操作。 每次操作给定 l, r, v,在 t[l..r] 的数组中插入元素v。 最后执行q次查询操作。 每次操作给定 l, r, k, 输出将t[l..r]排序后的第k大数

  • 1 <= n <= 1e9
  • 1 <= m, q <= 1e5
  • 1 <= l, r <= n
  • 1 <= v <= 1e9
  • 1 <= k <= 查询数组的元素总数
#include <bits/stdc++.h>
using namespace std;

using ll = long long;
// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2563

// Lazy seg

using S = pair<ll, int>;
using F = long long;
S op(S x, S y) {
    S s;
    s = S{x.first+y.first,x.second+y.second};
    return s;
}
S e() {
    return S();
};
S tag(F f, S s) { return S{s.first + f * s.second, s.second}; }
F merge(F x, F y) { return x + y; }
F id() { return 0; }

// Discrete

template<typename F, typename G, typename CHK> 
vector<int> paral_bs(int n, int q, F &&init, G &&apply,CHK &&check){
    vector<vector<int>> a(q);
    vector<int> l(n, -1), r(n, q);
    bool ok = 1;
    while (ok) {
      ok = 0;
      init();
      for (int i = 0; i < n; ++i) if (l[i] + 1 < r[i])
        a[(l[i] + r[i]) >> 1].push_back(i);
      for (int i = 0; i < q; ++i) {
        ok |= !a[i].empty();
        apply(i);
        for (int j : a[i]) {
          if (check(j)) r[j] = i;
          else l[j] = i;
        }
        a[i].clear();
      }
    }
    return r;
}

int main() {
    ios::sync_with_stdio(false); cin.tie(nullptr);
    int n, m, q;
    cin >> n >> m >> q;

    vector<int> a {0,1000000007};
    vector<array<int ,3>> op1(m);
    vector<array<int ,2>> op2(q);
    vector<long long> qs(q);
    
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < 3; ++j) {
          cin >> op1[i][j];
        }
        op1[i][0]--;
        a.push_back(op1[i][0]);
        a.push_back(op1[i][1]);
    }

    sort(op1.begin(), op1.end(), [&](auto &x, auto &y){
      return x[2] < y[2];
    });

    for (int i = 0; i < q; ++i) {
        cin >> op2[i][0] >> op2[i][1] >> qs[i];
        op2[i][0]--;
        a.push_back(op2[i][0]);
        a.push_back(op2[i][1]);
    }

    Discrete<int> v(a);
    
  vector<S> vp(v.size() - 1);
  for (int i = 0; i < v.size() - 1; ++i) {
    vp[i] = S{0, v[i + 1] - v[i]};
  }
  LazySegTree<S, op, e, F, tag, merge, id> seg(vp.size());

  for (int i = 0; i < m; ++i) {
    op1[i][0] = v(op1[i][0]);
    op1[i][1] = v(op1[i][1]);
  }
  for (int i = 0; i < q; ++i) {
    op2[i][0] = v(op2[i][0]);
    op2[i][1] = v(op2[i][1]);
  }

  auto init = [&](){
    for(int i = 0;i < vp.size(); ++i){
      seg.set(i, vp[i]);
    }
  };
  auto apply = [&](int i){
    seg.apply(op1[i][0], op1[i][1], 1);
  };
  auto chk = [&](int i){
    return seg.get(op2[i][0], op2[i][1]).first >= qs[i];
  };

  auto ans=paral_bs(q, m, init, apply, chk);
  
  for(int i = 0; i < q; i++) 
    cout << op1[ans[i]][2] << '\n';

    return 0;
}

datastructure

最小绝对值和

abc127 f

函数f(x),初始时 f(x)=0,q次查询

  • 1 a b 更新 f(x) 为 f(x) = f(x) + x - a + b
  • 2 输出 使f(x)取最小值的x,以及对应的f(x), 如果有多个,选最小的x。

可以证明,最小的x,总能在x为整数时取到,所以要求输出值为整数

  • 1 <= q <= 2e5
  • -1e9 <= a, b <= 1e9
template<typename T>
struct AbsSum{
    multiset<T> lp, rp;
    T s;
    AbsSum() : s(0) {}
    T insert(T x) {
        if (lp.empty()) {
            lp.insert(x), rp.insert(x);
            return T(0);
        }
        auto p = interval();
        lp.insert(x), rp.insert(x);
        if (p.first <= x and x <= p.second) return T(0);
        if (*lp.rbegin() > *rp.begin()) {
            T a = *lp.rbegin(), b = *rp.begin();
            lp.erase(lp.find(a));
            rp.erase(rp.find(b));
            rp.insert(a), lp.insert(b);
        }
        T res = min(abs(p.first - x), abs(p.second - x));
        s += res;
        return res;
    }
    T erase(T x) {
        assert(lp.count(x) + rp.count(x) >= 2);
        if (lp.count(x) and rp.count(x)) {
            lp.erase(lp.find(x)), rp.erase(rp.find(x));
            return T(0);
        }
        if (lp.count(x)) {
            lp.erase(lp.find(x));
            lp.erase(lp.find(x));
            lp.insert(*rp.begin());
            rp.erase(rp.begin());
        } else {
            rp.erase(rp.find(x));
            rp.erase(rp.find(x));
            rp.insert(*lp.rbegin());
            lp.erase(prev(lp.end()));
        }
        auto p = interval();
        if (p.first <= x and x <= p.second) return T(0);
        T res = min(abs(p.first - x), abs(p.second - x));
        s -= res;
        return res;
    }
    pair<T, T> interval() {
        assert(!lp.empty());
        return make_pair(*lp.rbegin(), *rp.begin());
    }
    T val() {return s;}
};

int main() {
    ios::sync_with_stdio(false); cin.tie(nullptr);
    int q;
    cin >> q;
    AbsSum<ll> p;
    long long s = 0;
    for (int i = 0, t; i < q; ++i) {
        cin >> t;
        if (t == 1) {
            long long x, y;
            cin >> x >> y;
            p.insert(x);
            s += y;
        } else {
            cout << p.interval().first << " " << s + p.val() << '\n';
        }
    }
    return 0;
}

前k大元素和

arc 074D

给定长度为3*N的数组a,需要从中删除N个元素,剩余2N个元素保持原有顺序不变,求剩余元素前N个元素和减去后N个元素和的最大值。

  • 1 <= N <= 1e5
  • 1 <= a[i] <= 1e9

PrioritySum

PrioritySum 数据结构维护维护多个元素的前k大(前k小)的元素之和。

#include <bits/stdc++.h>
using namespace std;

using ll = long long;

template <typename T, typename Com = less<T> , typename RCom = greater<T>>
struct PrioritySum {
    PrioritySum() : PrioritySum(0) {}
    PrioritySum(int k) : _k(k), sum(0){}

    T query() const { return sum; }
    void push(const T &v) { sum += v; in.push(v); fix();}
    void erase(const T &v) {
        if (in.size() and v == in.top()) { sum -= v; in.pop(); } 
        else if (in.size() and _rev_cmp(v, in.top())) { sum -= v; d_in.push(v);} 
        else d_out.push(v);
        fix();
    }
    int get_k() const { return _k; }
    void set_k(int new_k) { _k = new_k, fix(); }
    int size() const { return int((in.size() + out.size()) - (d_in.size() + d_out.size())); }
private:
    int _k;
    T sum;
    priority_queue<T, vector<T>, Com> in, d_in;
    priority_queue<T, vector<T>, RCom> out, d_out;
    void fix() {
        while (int(in.size() - d_in.size()) < _k and out.size()) {
            T v = move(out.top()); out.pop();
            if (d_out.size() and d_out.top() == v) d_out.pop();
            else { sum += v; in.push(move(v));}
        }
        while (int(in.size() - d_in.size()) > _k) {
            T v = move(in.top()); in.pop();
            if (d_in.size() and d_in.top() == v) d_in.pop();
            else { sum -= v; out.push(move(v));}
        }
    }
};
template <typename T> using MaxSum = PrioritySum<T, greater<T>, less<T>>;
template <typename T> using MinSum = PrioritySum<T, less<T>, greater<T>>;


int main() {
    ios::sync_with_stdio(false); cin.tie(nullptr);
    int n;
    cin >> n;
    vector<int> a(3 * n);
    for (int &x : a) 
        cin >> x;
    MaxSum<ll> q1(n);
    MinSum<ll> q2(n);
    vector<long long> f(3 * n), g(3 * n);
    for (int i = 0; i < 3 * n; ++i) {
        if (i >= n) f[i] = q1.query();
        q1.push(a[i]);
    }
    for (int i = 3 * n - 1; i >= 0; --i) {
        q2.push(a[i]);
        if (i <= 2 * n) g[i] = q2.query();
    }
    ll ans = -1e18;
    for (int i = n; i <= 2 * n; ++i)
        ans = max(ans, f[i] - g[i]);
    cout << ans;
    return 0;
}

离线矩形加矩形求和

rectangle sum

有一个1e9*1e9的矩阵,初始元素全为0,首先进行n次操作接着执行q个查询,每次操作 x1 y1 x2 y2 w[x1,x2]*[y1.y2]矩形内的所有元素执行a[i][j] += w。 每次查询给定 x1 y1 x2 y2 ,求矩形内的元素总和 模 998244353.

#include <bits/stdc++.h>
using namespace std;

using ll = long long;

// FenwickTree
// Discrete
// mint

 namespace internal::tuple_ops {
    template <size_t N, typename F, typename ...Args>
    tuple<Args...>& update(tuple<Args...>& lhs, F&& fun) {
        if constexpr (N == tuple_size_v<tuple<Args...>>) return lhs;
        else return fun(get<N>(lhs)), update<N + 1>(lhs, forward<F>(fun));
    }
    template <size_t N, typename F, typename ...Args>
    tuple<Args...>& merge(tuple<Args...>& lhs, const tuple<Args...>& rhs, F&& fun) {
        if constexpr (N == tuple_size_v<tuple<Args...>>) return lhs;
        else return fun(get<N>(lhs), get<N>(rhs)), merge<N + 1>(lhs, rhs, forward<F>(fun));
    }
}
template <typename ...Args>
tuple<Args...>& operator+=(tuple<Args...>& t1, const tuple<Args...>& t2) {
    return internal::tuple_ops::merge<0>(t1, t2, [](auto& x, const auto& y) { x += y; });
}
template <typename ...Args>
tuple<Args...>& operator-=(tuple<Args...>& t1, const tuple<Args...>& t2) {
    return internal::tuple_ops::merge<0>(t1, t2, [](auto& x, const auto& y) { x -= y; });
}
template <typename ...Args>
tuple<Args...> operator+(tuple<Args...> t1, const tuple<Args...>& t2) { return move(t1 += t2); }
template <typename ...Args>
tuple<Args...> operator-(tuple<Args...> t1, const tuple<Args...>& t2) { return move(t1 -= t2); }

template <typename V, typename ...Args>
tuple<Args...>& operator*=(tuple<Args...>& t1, const V& v) { return internal::tuple_ops::update<0>(t1, [&v](auto& x) { x *= v; }); }
template <typename V, typename ...Args>
tuple<Args...>& operator/=(tuple<Args...>& t1, const V& v) { return internal::tuple_ops::update<0>(t1, [&v](auto& x) { x /= v; }); }

template <typename V, typename ...Args>
tuple<Args...> operator*(const V& v, tuple<Args...> t1) { return move(t1 *= v); }
template <typename V, typename ...Args>
tuple<Args...> operator*(tuple<Args...> t1, const V& v) { return move(t1 *= v); }
template <typename V, typename ...Args>
tuple<Args...> operator/(tuple<Args...> t1, const V& v) { return move(t1 /= v); }

template <typename T>
struct StaticRectSum {
    int q;
    vector<tuple<int, int, T>> suf_querys;
    vector<tuple<int, int, int, bool>> pre_sums;
    vector<int> ys;
    StaticRectSum() : q(0) {}
    StaticRectSum(int n, int q) : q(q) { suf_querys.reserve(4 * n); pre_sums.reserve(4 * q); ys.reserve(2 * n);}

    void add_sum(int x1, int y1, int x2, int y2, T val) {
        ys.emplace_back(y1); ys.emplace_back(y2);
        suf_querys.emplace_back(x1, y1, val), suf_querys.emplace_back(x2, y1, -val);
        suf_querys.emplace_back(x1, y2, -val), suf_querys.emplace_back(x2, y2, val);
    }
    void add_query(int x1, int y1, int x2, int y2, int idx) {
        pre_sums.emplace_back(x1, y1, idx, true), pre_sums.emplace_back(x2, y1, idx, false);
        pre_sums.emplace_back(x1, y2, idx, false), pre_sums.emplace_back(x2, y2, idx, true);
    }

    vector<T> get() {
        static constexpr auto x_comp = [](const auto& q1, const auto& q2) { return std::get<0>(q1) < std::get<0>(q2); };
        sort(suf_querys.begin(), suf_querys.end(), x_comp);
        sort(pre_sums.begin(), pre_sums.end(), x_comp);

        Discrete<int> vd(ys);
        FenwickTree<tuple<T, T, T, T>> ft(vd.size());
        vector<T> res(q, T{ 0 });
        int n = suf_querys.size(), m = pre_sums.size();
        for (int i = 0, j = 0; i < n or j < m;) {
            if (j == m or (i < n and x_comp(suf_querys[i], pre_sums[j]))) {
                const auto& [l, d, v] = suf_querys[i++];
                ft.add(vd(d),{ v, -v * d, -v * l, v * l * d });
            } else {
                const auto& [x, y, qid, is_add] = pre_sums[j++];
                auto [a, b, c, d] = ft.sum(0, vd(y) - 1);
                const T sum = a * x * y + b * x + c * y + d;
                if (is_add) res[qid] += sum;
                else        res[qid] -= sum;
            }
        }
        return res;
    } 
};

int main() {
    ios::sync_with_stdio(false); cin.tie(nullptr);
    int n, q;
    cin >> n >> q;
    StaticRectSum<mint> s(n, q);
    for (int i = 0, x1, y1, x2, y2, w; i < n; ++i) {
        cin >> x1 >> y1 >> x2 >> y2 >> w;
        s.add_sum(x1, y1, x2, y2, w);
    }
    for (int i = 0, x1, y1, x2, y2; i < q; ++i) {
        cin >> x1 >> y1 >> x2 >> y2;
        s.add_query(x1, y1, x2, y2, i);
    }
    auto ans = s.get();
    for (int i = 0; i < q; ++i) {
        cout << ans[i] << "\n";    
    }
    return 0;
}

带修改子数组不同元素数量和

hackranker

给定数组a,f(l,r) 表示子数组a[l:r]中包含的不同元素数目,设所有子数组的f(l,r)之和为s,Q次修改,每次修改给定k,x,赋值a[k]=x, 输出每次修改操作后的s的值。

  • 1 <= n, q <= 1e5
  • 1 <= a[i], x <= 1e9
  • 0 <= k < n
template <typename T>
struct DistinctArrSum {
    int n;
    vector<T> a;
    long long ans;
    map<T, set<int>> mp;
    DistinctArrSum(int n) : n(n), a(n) {init();}
    DistinctArrSum(vector<T> &b) {
        n = b.size();
        a = b;
        init();
    }
    long long count(int x) const {
        return 1ll * x * (x + 1) / 2;
    }
    void init() {
        ans = 0;
        for (int i = 0; i < n; ++i) 
            mp[a[i]].insert(i);
        for (auto &[k, v] : mp) {
            long long s = count(n);
            int last = -1;
            for (auto &x : v) {
                if (last == -1) {
                    if (x > 0) s -= count(x);
                } else s -= count(x - last - 1);
                last = x;
            }
            if (last < n - 1) s -= count(n - 1 - last);
            ans += s;
        }
    }
    void del(int k) { // del a[k],0<=k<n
        assert(k >= 0 && k < n && mp.count(a[k]));
        std::set<int> &s = mp[a[k]];
        if (s.size() == 1) {
            mp.erase(a[k]);
            ans -= count(n);
            if (k > 0) ans += count(k);
            if (k < n - 1) ans += count(n - 1 - k);
            return;
        }
        auto it = s.lower_bound(k);
        if (it == s.begin()) {
            if (k > 0) ans += count(k);
            int next_val = *next(it);
            ans += count(next_val - k - 1) - count(next_val);
        } else {
            auto nxt = next(it);
            int pre_val = *prev(it);
            if (nxt == s.end()) {
                if (k < n - 1) ans += count(n - 1 - k);
                ans += count(k - pre_val - 1) - count(n - 1 - pre_val);
            } else {
                int next_val = *nxt;
                ans += count(k - pre_val - 1) + count(next_val - k - 1) - count(next_val - pre_val - 1);
            }
        }
        s.erase(k);
    }
    void add(int k, int x) { // mp[x] add index k
        if (!mp.count(x)) {
            mp[x].insert(k);
            ans += count(n);
            if (k > 0) ans -= count(k);
            if (k < n - 1) ans -= count(n - 1 - k);
            return;
        }
        auto &s = mp[x];
        auto it = s.lower_bound(k);
        if (it == s.begin()) {
            int old_front = *it;
            ans += count(old_front) - count(old_front - k - 1);
            if (k > 0) ans -= count(k);
        } else if (it == s.end()){
            int pre_val = *prev(it);
            ans += count(n - 1 - pre_val) - count(k - pre_val - 1);
            if (k < n - 1) ans -= count(n - 1 - k);
        } else {
            int pre_val = *prev(it), next_val = *it;
            ans += count(next_val - pre_val - 1) - count(k - pre_val - 1) - count(next_val - k - 1);
        }
        s.insert(k);
    }
    void upd(int k, T x) { // 0 <= k < n, set a[k] = x;
        if (a[k] == x) return;
        del(k);
        add(k, x);
        a[k] = x;
    }
    long long get() const { // total distinct number sum of all subarray
        return ans;
    }
};

void solve(int tt) {
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }
    DistinctArrSum<int> p(a);
    cin >> q;
    for (int i = 0; i < q; ++i) {
        cin >> k >> x;
        p.upd(k, x);
        cout << p.get() << '\n';
    }
}

区间与等差数列和

维护多次操作,每次操作给定 l, r a, d, 将区间[l,r]中的元素与以a为首项,d为公差的等差数列相加。

离线

先执行完所有操作,再查询每个位置对应元素。 可以用差分数组维护,时间复杂度 O(n)

template <typename T>
struct RangeGeoSum {
    int n;
    vector<T> d1, d2;
    RangeGeoSum(int N) : n(N), d1(N), d2(N) {}
    RangeGeoSum(vector<T> &A) : RangeGeoSum((int)A.size()) {
        for (int i = 0; i < n; ++i) d2[i] = A[i];
    }
    void add(int l, int r, const T a1, const T &d) { //[l,r) 首项为a1,公差为d的等差数列
        d1[l] += d;
        d2[l] += a1 - d * l;
        if (r < n) {
            d1[r] -= d;
            d2[r] -= a1 - d * l;
        }
    }
    vector<T> get() {
        vector<T> ret(n);
        for (int i = 0; i < n; ++i) {
            ret[i] = d1[i] * i + d2[i];
            if (i < n - 1) {
                d1[i + 1] += d1[i];
                d2[i + 1] += d2[i];
            }
        }
        return ret;
    }
};

使用方法

  1. 定义数据结构

RangeGeoSum<ll> f(n);

  1. 对区间[l, r-1],元素与以a为首项,d为公差的等差数列相加

f.add(l, r, a, d);

  1. 获取最终操作后的数组

auto d = f.get();

例题

cf 819b

给定一个排列p,可以将p进行循环移位, 求 p1-1 + p2-2 +…+ pn-n 的最小值。
  • 1 <= n <= 1e6

分析

考虑每个数的贡献,其在小于自身的位置 x时,其对结果的贡献为 p[i]-x,否则,在大于自身的位置时,其对结果的贡献为 x-p[i]。 而其位置的变化是从 i逐次增大变为n,再从 1出发不断增大变为 i - 1,即整体除了一点外是连续的变化。每一段都是一个区间与一个等差数列求和的形式。

int main() {    
    int n;
    cin >> n;
    vector<int> p(n);
    for (int i = 0; i < n; ++i) {
        cin >> p[i];
        p[i]--;
    }

    RangeGeoSum<ll> f(n);

    for (int i = 0; i < n; ++i) {
        if (p[i] > i) {
            f.add(0, p[i] - i + 1, p[i] - i, -1);
            int r = min(n, p[i] - i + n - p[i]);

            if (p[i] - i + 1 < r) {
                f.add(p[i] - i + 1, r, 1, 1);
            }

            if (r < n) {
                f.add(r, n, p[i], -1);
            }

        } else {
            f.add(0, n - i, i - p[i], 1);

            int r = min(n - i + p[i] + 1, n);
            if (n - i < r) {
                f.add(n - i, r, p[i], -1);
            }

            if (r < n) {
                f.add(r, n, 1, 1);
            }
        }
    }

    long long mn = 1e18;
    int id = -1;
    auto d = f.get();
    for (int i = 0; i < n; ++i) {
        if (d[i] < mn) {
            mn = d[i];
            id = i;
        }
    }

    cout << mn << ' ' << id << '\n';

    return 0;
}

在线

边操作,边访问某个下标处的元素,这是可以使用树状数组 rangeAddTree 维护区间加和,可以 log(n) 时间内访问下标处的元素。

string

runenumerate

runenumerate

长度为n的字符串s,输出字符串s的所有runs, 输出 [t, l, r]的数组。 表示s的子串[l,..r-1] 是最大的以t为最小长度的周期串,且 len(s) >= 2t, 例如 abcabca 是以abc为周期的串。

  • 1 <= s <= 2e5
// z_function

struct Run {
    int period;
    int l, r;
    Run() = default;
    Run(int period, int l, int r) : period(period), l(l), r(r) {}
    friend bool operator<(const Run& r1, const Run& r2) {
        return r1.period != r2.period ? r1.period < r2.period : r1.l != r2.l ? r1.l < r2.l : r1.r < r2.r;
    }
    friend bool operator>(const Run& r1, const Run& r2) { return r2 < r1; }
    friend bool operator<=(const Run& r1, const Run& r2) { return not (r2 < r1); }
    friend bool operator>=(const Run& r1, const Run& r2) { return not (r1 < r2); }
    friend bool operator==(const Run& r1, const Run& r2) { return r1.period == r2.period and r1.l == r2.l and r1.r == r2.r; }
    friend bool operator!=(const Run& r1, const Run& r2) { return not (r1 == r2); }
};

template <typename Container, typename = void_t<typename Container::value_type>>
vector<Run> run_enum(Container& s, typename Container::value_type sentinel = numeric_limits<typename Container::value_type>::min()) {
    for (auto& e : s) assert(e != sentinel);
    using T = typename Container::value_type;

    vector<Run> glob_result;
    auto div_conq = [&](auto div_conq, int l, int r) -> vector<Run> {
        if (r - l <= 1) return {};
        const int m = (l + r) >> 1;
        vector<Run> run_l = div_conq(div_conq, l, m), run_r = div_conq(div_conq, m, r);

        string rl;
        copy(begin(s) + m, begin(s) + r, back_inserter(rl));
        rl.push_back(sentinel);
        copy(begin(s) + l, begin(s) + m, back_inserter(rl));
        vector<int> z_rl = z_function(rl);

        reverse(begin(rl), end(rl));
        vector<int> z_rl_rev = z_function(rl);

        const int siz = rl.size();

        vector<Run> result;

        auto add_ans = [&](Run&& run) { (run.l == l or run.r == r ? result : glob_result).emplace_back(move(run)); };

        const int len_l = m - l, len_r = r - m;
        vector<Run> run_m(len_r / 2 + 1);
        for (auto& run : run_r) {
            if (run.l != m) {
                add_ans(move(run));
                continue;
            }
            run_m[run.period] = move(run);
        }
        for (auto& run : run_l) {
            if (run.r != m) {
                add_ans(move(run));
                continue;
            }
            const int period = run.period;
            if (z_rl[siz - period] == period) {
                if (run_m[period].period) {
                    run.r = run_m[period].r;
                    run_m[period] = Run{};
                    add_ans(move(run));
                } else {
                    run.r = m + period + z_rl[period];
                    add_ans(move(run));
                }
            } else {
                run.r = m + z_rl[siz - period];
                add_ans(move(run));
            }
        }
        for (auto& run : run_m) if (run.period) {
            const int period = run.period;
            if (z_rl[siz - period] == period) {
                if (2 * period <= len_l and z_rl[siz - 2 * period] >= period) continue;
                run.l = m - period - z_rl_rev[period];
                add_ans(move(run));
            } else {
                run.l = m - z_rl_rev[siz - period];
                add_ans(move(run));
            }
        }

        for (int period = 1; period <= len_l; ++period) {
            bool skip_r = 2 * period <= len_r and z_rl[period] >= period;
            bool skip_l = 2 * period <= len_l and z_rl[siz - 2 * period] >= period;
            if (z_rl[siz - period] == period) {
                if (skip_l or skip_r) continue;

                const int beg_pos = m - period - z_rl_rev[period];
                const int end_pos = m + period + z_rl[period];
                add_ans(Run{ period, beg_pos, end_pos });
            } else {
                if (not skip_r) {
                    const int beg_pos = m - z_rl_rev[siz - period];
                    const int end_pos = m + period + z_rl[period];
                    if (end_pos - beg_pos >= 2 * period) {
                        add_ans(Run{ period, beg_pos, end_pos });
                    }
                }
                if (not skip_l) {
                    const int beg_pos = m - period - z_rl_rev[period];
                    const int end_pos = m + z_rl[siz - period];
                    if (end_pos - beg_pos >= 2 * period) {
                        add_ans(Run{ period, beg_pos, end_pos });
                    }
                }
            }
        }
        return result;
    };
    const int n = s.size();
    vector<tuple<int, int, int>> runs;
    for (Run& run : div_conq(div_conq, 0, n)) {
        runs.emplace_back(run.l, run.r, run.period);
    }
    for (Run& run : glob_result) {
        runs.emplace_back(run.l, run.r, run.period);
    }
    sort(begin(runs), end(runs));
    runs.erase(
        unique(
            begin(runs), end(runs),
            [](auto& r1, auto& r2) {
                return get<0>(r1) == get<0>(r2) and get<1>(r1) == get<1>(r2);
            }
        ), end(runs)
                );
    vector<Run> res;
    for (auto& [l, r, t] : runs) res.emplace_back(t, l, r);
    return res;
}

打赏一下

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦