特集:セグメントツリー

長すぎるセグメントツリー手が生まれてきた再生しないでください

問題A:高速道路

偽所望のタイトル、明らかに分母\(R&LT C_ { - }。1 + L ^ 2 \) 全てのサブセグメント区間内と求めてすべてがあります。

そして、ツリーライン区間の合併を検討し、それを行うように見えることはできません。

そして、SXレッドサン郭は私を啓発する、我々は染色に似ツリーのアイデアを取ることができ、各エッジは、いくつかの後にすることができ考えます。

以下のために、比較した場合、これは明らかである\((R - I + 1 - )(I L + 1)\) その分子である。\(\ SUM \ _制限} {I = L ^ R&LT(R&LT - + I. 1) (I - 1 + L)W_i \)

簡略化は、約\(\ SUM \ _制限} {I = L ^ R&LT(R&LT - 1 + L - LR)W_i +(L + R&LT)W_i I - I 2 W_i ^ \)

3セグメントツリータグに注意してください。\(= W_i S_1、S_2 I = W_i、W_i S_3 = I ^ 2 \)

間隔は一緒に直接組み込みます。

そして、右側の変更を検討し、それを追加することです\(V(R&LTを- 。1 + L - LR)\) \(I SUM \ V(L + R&LT)\)と$ -VI ^ 2 $。

再记\(S_4 =合計I、S_5 = \合計\ I ^ 2 \)

この質問は終了されるだろう。

ピットに注意してください。

  1. その時点までに、私たちはそのラインを維持し、我々はそれに対処する必要があります
  2. 長い長い長い長い開くために開くことができます!躊躇しないでください!あなたWA20あれば、それは長い長い開かなかった開くしようとしています
#include <bits/stdc++.h>
#define ll long long

const int N = 100000 + 233;
ll n, m, sum[5]; char opt[5];
struct SegTree { ll l, r, s[8], tag; } t[N << 2];

inline void Pushup(ll p) {
    for (int i = 1; i <= 3; i++)
        t[p].s[i] = t[p << 1].s[i] + t[p << 1 | 1].s[i];
}

ll gcd(ll x, ll y) {
    return y == 0 ? x : gcd(y, x % y);
}

void Build(ll p, ll l, ll r) {
    t[p].l = l, t[p].r = r;
    if (l == r) return (void) (t[p].s[4] = l, t[p].s[5] = l * l);
    ll mid = (l + r) >> 1;
    Build(p << 1, l, mid), Build(p << 1 | 1, mid + 1, r);
    for (int i = 4; i <= 5; i++)
        t[p].s[i] = t[p << 1].s[i] + t[p << 1 | 1].s[i];
}

inline void Add(ll p, ll k) {
    t[p].s[1] += (t[p].r - t[p].l + 1) * k;
    t[p].s[2] += k * t[p].s[4];
    t[p].s[3] += k * t[p].s[5];
    t[p].tag += k;
}

inline void Pushdown(ll p) {
    Add(p << 1, t[p].tag), Add(p << 1 | 1, t[p].tag);
    t[p].tag = 0;
}

void Change(ll p, ll l, ll r, ll v) {
    if (l <= t[p].l && r >= t[p].r) return (void) Add(p, v);
    ll mid = (t[p].l + t[p].r) >> 1;
    if (t[p].tag) Pushdown(p);
    if (l <= mid) Change(p << 1, l, r, v);
    if (r > mid) Change(p << 1 | 1, l, r, v);
    Pushup(p);
}

void Ask(ll p, ll l, ll r) {
    if (l <= t[p].l && r >= t[p].r) {
        for (int i = 1; i <= 3; i++)
            sum[i] += t[p].s[i];
        return;
    }
    ll mid = (t[p].l + t[p].r) >> 1;
    if (t[p].tag) Pushdown(p);
    if (l <= mid) Ask(p << 1, l, r);
    if (r > mid) Ask(p << 1 | 1, l, r);
}

inline void print(ll x, ll y) {
    ll g = gcd(x, y);
    printf("%lld/%lld\n", x / g, y / g);
}

signed main() {
    scanf("%lld%lld", &n, &m);
    Build(1, 1, n);
    for (ll i = 1, l, r; i <= m; i++) {
        ll v;
        scanf("%s%lld%lld", opt, &l, &r); r--;
        if (opt[0] == 'C') {
            scanf("%lld", &v), Change(1, l, r, v);
        } else {
            sum[1] = sum[2] = sum[3] = 0;
            Ask(1, l, r);
            ll a = (r - l + 1 - l * r) * sum[1] + (r + l) * sum[2] - sum[3];
            ll b = (r - l + 2) * (r - l + 1) / 2;
            print(a, b);
        }
    }
    return 0;
}

問題D:ソート

第四に(この問題に耳を傾け

死の家の興Zeyuの最初の審理はSJZEZを話します

SDFZでの2勝目は、高低温の鳩鳩の話を聞きます

TYWZで三回目は本当に赤い日リカルド-SXを聴いて話すために一緒に取得

第四に巨大な巨大なコアラはHZに話を聞きます

本当の公共の問題(

この質問の最も重要な点は、一箇所だけを依頼することです、と答えは明確に単調である、あなたは半分に逃げます

配列をソートすることは、セグメントツリーと「ソート」プロセスを維持できるように、0より大きく、1以下表し、01の配列に変わり、あまりにチを研削します。

しかし、行くことができるどのような水、バケツ行の最適化神を超えるデータの問題(((

#include <bits/stdc++.h>

const int N = 100005 + 233;
int n, m, q, ans, a[N];
struct Command { int l, r, op; } cmd[N];
struct SegTree {
    int l, r, sum, tag;
    #define l(p) tree[p].l
    #define r(p) tree[p].r
    #define sum(p) tree[p].sum
    #define tag(p) tree[p].tag
    #define ls(p) p << 1
    #define rs(p) p << 1 | 1
} tree[N << 2];

inline int R() {
    int a = 0; char c = getchar();
    while (!isdigit(c)) c = getchar();
    while (isdigit(c)) a = a * 10 + c - '0', c = getchar();
    return a;
}

void Build(int p, int l, int r, int v) {
    l(p) = l, r(p) = r, tag(p) = -1;
    if (l == r) return (void) (sum(p) = a[l] >= v);
    int mid = (l + r) >> 1;
    Build(ls(p), l, mid, v), Build(rs(p), mid + 1, r, v);
    sum(p) = sum(ls(p)) + sum(rs(p));
}

void Pushdown(int p) {
    if (tag(p) != -1) {
        sum(ls(p)) = (r(ls(p)) - l(ls(p)) + 1) * tag(p);
        sum(rs(p)) = (r(rs(p)) - l(rs(p)) + 1) * tag(p);
        tag(ls(p)) = tag(rs(p)) = tag(p);
        tag(p) = -1;
    }
}

void Change(int p, int l, int r, int v) {
    if (l <= l(p) && r >= r(p)) {
        sum(p) = (r(p) - l(p) + 1) * v;
        tag(p) = v;
    } else {
        Pushdown(p);
        int mid = (l(p) + r(p)) >> 1;
        if (l <= mid) Change(ls(p), l, r, v);
        if (r > mid) Change(rs(p), l, r, v);
        sum(p) = sum(ls(p)) + sum(rs(p));
    }
}

int Query(int p, int l, int r) {
    if (l <= l(p) && r >= r(p)) 
        return sum(p);
    Pushdown(p);
    int mid = (l(p) + r(p)) >> 1, ret = 0;
    if (l <= mid) ret += Query(ls(p), l, r);
    if (r > mid) ret += Query(rs(p), l, r);
    return ret;
}

bool Check(int x) {
    Build(1, 1, n, x);
    for (int i = 1; i <= m; i++) {
        int cnt = Query(1, cmd[i].l, cmd[i].r);
        if (cnt != 0 && cnt != cmd[i].r - cmd[i].l + 1) {
            if (cmd[i].op) {
                Change(1, cmd[i].l, cmd[i].l + cnt - 1, 1);
                Change(1, cmd[i].l + cnt, cmd[i].r, 0);
            } else {
                Change(1, cmd[i].l, cmd[i].r - cnt, 0);
                Change(1, cmd[i].r - cnt + 1, cmd[i].r, 1);
            }
        }
    }
    return Query(1, q, q);
}

signed main() {
    n = R(), m = R();
    for (int i = 1; i <= n; i++)
        a[i] = R();
    for (int i = 1; i <= m; i++)
        cmd[i].op = R(), cmd[i].l = R(), cmd[i].r = R();
    q = R();
    int l = 1, r = n, mid;
    while (l <= r) {
        mid = (l + r) >> 1;
        if (Check(mid)) {
            ans = mid;
            l = mid + 1;
        } else r = mid - 1;
    }
    return !printf("%d\n", ans);
}

おすすめ

転載: www.cnblogs.com/gekoo/p/11240280.html