Codechef MARCH20A:月チャレンジ2020ディビジョン1

トピックは必ずしも難易度の一種ではありません。私が質問に表面のすべての中国のポイントを得ます

SPORTS

それは容易に二次元の半順序に変換されます。時間の複雑さはある\(\ mathcal O((N + Q)\ Nをログ)\)

#include <cstdio>
#include <algorithm>

const int MN = 100005, MQ = 100005;

int N, Q, A[MN], lb[MQ], rb[MQ], y[MQ], qp[MQ], Ans[MQ];
int op[MN * 2], id[MN * 2], yp[MN * 2], pp[MN * 2], C;
int bit[MN];
inline void Add(int i, int x) { for (; i < N; i += i & -i) bit[i] += x; }
inline int Qur(int i) { int a = 0; for (; i; i -= i & -i) a += bit[i]; return a; }

int main() {
    int Tests;
    scanf("%d", &Tests);
    while (Tests--) {
        scanf("%d%d", &N, &Q), C = 0;
        for (int i = 1; i <= N; ++i) scanf("%d", &A[i]);
        for (int i = 1; i <= Q; ++i) scanf("%d%d%d", &lb[i], &rb[i], &y[i]), qp[i] = i;
        for (int i = 1; i < N; ++i)
            op[++C] = 0, id[C] = i, yp[C] = std::min(A[i], A[i + 1]), pp[C] = C,
            op[++C] = 1, id[C] = i, yp[C] = std::max(A[i], A[i + 1]), pp[C] = C;
        std::sort(pp + 1, pp + C + 1, [](int i, int j) { return yp[i] == yp[j] ? op[i] < op[j] : yp[i] < yp[j]; });
        std::sort(qp + 1, qp + Q + 1, [](int i, int j) { return y[i] < y[j]; });
        for (int i = 1; i < N; ++i) bit[i] = 0;
        for (int I = 1, J = 1; I <= Q; ++I) {
            while (J <= C && (yp[pp[J]] < y[qp[I]] || (yp[pp[J]] == y[qp[I]] && op[pp[J]] == 0)))
                Add(id[pp[J]], op[pp[J]] ? -1 : 1), ++J;
            Ans[qp[I]] = Qur(rb[qp[I]] - 1) - Qur(lb[qp[I]] - 1);
        }
        for (int i = 1; i <= Q; ++i) printf("%d\n", Ans[i]);
    }
    return 0;
}

LAZERTST

精神の問題は、最初のサブタスクの出力\(M - 1 \)は、二つのサブタスクの後に、各質問を求めた(M / 2 \)\丸め下、その後、直接答えを返します。

#include <cstdio>

const int MQ = 15;

int M, Q, L[MQ], R[MQ], Ans[MQ];

int main() {
    int Tests;
    scanf("%d", &Tests);
    while (Tests--) {
        scanf("%*d%d%*d%d", &M, &Q);
        for (int i = 1; i <= Q; ++i) scanf("%d%d", &L[i], &R[i]);
        for (int i = 1; i <= Q; ++i) {
            if (M <= 10 && R[i] - L[i] >= 1000) {
                Ans[i] = M - 1;
            } else {
                printf("1 %d %d %d\n", L[i], R[i], M / 2);
                fflush(stdout);
                scanf("%d", &Ans[i]);
            }
        }
        printf("2");
        for (int i = 1; i <= Q; ++i) printf(" %d", Ans[i]);
        printf("\n"), fflush(stdout);
        scanf("%*d");
    }
    return 0;
}

夜が明けました

使用\(\ mathcal O(KN ^ 2)\) 時間はすべての側面から選択することができ、決定することができます。

最終的なエッジは、各ブロックの通信ニーズは、ツリー内に形成され、さらに状態を観察しました。

しかしながら、ツリー分割ツリー鎖、及び側鎖の間にあっても断線場合、数は、実際に非度に(葉)ノードに影響を及ぼしません。

その後、チェーンが最小カバレッジを探している、既知のチェーンカバーが最小DAGに等しい\(N- \)二部グラフに変換されるマッチの数を減算します。

使用Dinicマッチングアルゴリズムは、時間計算量は\(\ mathcal O 2)\(N ^)

#include <cstdio>
#include <algorithm>

namespace DinicFlows {
    typedef long long LL;
    const LL Inf = 0x3f3f3f3f3f3f3f3f;
    const int MN = 4005, MM = 1999005;
    
    int N, S, T;
    int h[MN], iter[MN], nxt[MM * 2], to[MM * 2], tot; LL w[MM * 2];
    
    inline void SetST(int _S, int _T) { S = _S, T = _T; }
    inline void Init(int _N) {
        N = _N, tot = 1;
        for (int i = 1; i <= N; ++i) h[i] = 0;
        SetST(_N - 1, _N);
    }
    
    inline void ins(int u, int v, LL x) {
        if (tot + 1 >= MM * 2) { puts("Error : too many edges."); return ; }
        nxt[++tot] = h[u], to[tot] = v, w[tot] = x, h[u] = tot;
    }
    inline void insw(int u, int v, LL w1 = Inf, LL w2 = 0) {
        if (!u) u = S; if (!v) v = T;
        ins(u, v, w1), ins(v, u, w2);
    }
    
    int lv[MN], que[MN], l, r;
    
    inline bool Lvl() {
        for (int i = 1; i <= N; ++i) lv[i] = 0;
        lv[S] = 1;
        que[l = r = 1] = S;
        while (l <= r) {
            int u = que[l++];
            for (int i = h[u]; i; i = nxt[i])
                if (w[i] && !lv[to[i]]) {
                    lv[to[i]] = lv[u] + 1;
                    que[++r] = to[i];
                }
        }
        return lv[T] != 0;
    }
    
    LL Flow(int u, LL f) {
        if (u == T) return f;
        LL d = 0, s = 0;
        for (int &i = iter[u]; i; i = nxt[i])
            if (w[i] && lv[to[i]] == lv[u] + 1) {
                d = Flow(to[i], std::min(f, w[i]));
                f -= d, s += d;
                w[i] -= d, w[i ^ 1] += d;
                if (!f) break;
            }
        return s;
    }
    
    inline LL Dinic() {
        LL Ans = 0;
        while (Lvl()) {
            for (int i = 1; i <= N; ++i) iter[i] = h[i];
            Ans += Flow(S, Inf);
        }
        return Ans;
    }
}
using DinicFlows::insw;
using DinicFlows::to;

const int MN = 2005;

int N, K, C[MN][MN], Z[MN];

int main() {
    int Tests;
    scanf("%d", &Tests);
    while (Tests--) {
        scanf("%d%d", &N, &K);
        for (int i = 1; i <= N; ++i)
            for (int j = 1; j <= N; ++j)
                C[i][j] = 0;
        for (int k = 1; k <= K; ++k) {
            for (int i = 1; i <= N; ++i) scanf("%d", &Z[i]);
            for (int i = 1; i < N; ++i)
                for (int j = i + 1; j <= N; ++j)
                    ++C[Z[i]][Z[j]];
        }
        DinicFlows::Init(2 * N + 2);
        for (int i = 1; i <= N; ++i) insw(0, i, 1), insw(N + i, 0, 1);
        for (int i = 1; i <= N; ++i)
            for (int j = 1; j <= N; ++j)
                if (C[i][j] == K) insw(i, N + j, 1);
        printf("%lld\n", N - DinicFlows::Dinic());
        for (int i = 1; i <= N; ++i) {
            int ans = 0;
            for (int j = DinicFlows::h[i], u; j; j = DinicFlows::nxt[j])
                if ((u = DinicFlows::to[j] - N) <= N && !DinicFlows::w[j]) { ans = u; break; }
            printf("%d ", ans);
        }
        puts("");
    }
    return 0;
}

MDSWIN2

常にこの区間でのゲームの組み合わせを行うことです範囲を尋ねます。

前にこの間隔で表示される要素の場合、それはニム、それはこの期間中に出現する回数のゲームで石の山として見ることができます。

MOアルゴリズムが使用チームであってもよい\(\ mathcal O(Q + N \ SQRT {Q})\) の期間内に石の数、各スタックを維持するだけでなく、維持するために、\(\ mathrm {SG} \ ) 値。

もし(\ \ mathrm {SG} \ ) である\(0 \) 答えは当然である\(0 \) 上側のハンドを失うからです。

そうでなければ、私たちが考える、答えは等しくなければなりません\(\ DisplayStyle \ sum_ {I} \ Binom C_I {} {C_I \ oplus \ mathrm {SG}} \)
これは、石の山は、この数を必要とする、石のすべての山を列挙することである(C_I \)\となり(C_I \ oplus \ mathrm {SG} \)\新しい作るために、\(\ mathrm {SG}を\ )値となる(0 \)\、のためのプログラムの数(\ \ DisplayStyle \ Binom C_I {} {C_I \ Oplus \ mathrm {SG}} \)

このことは、ブロックの大きさを考慮して、良いメンテナンスではありません。

元の配列における出現のすべての数値を超えていないため\(S = \ mathcal O( \ SQRT {N})\) 小石ヒープスタック、そうでなければ杭を前記に対応する番号を、。

我々はサイズを使用して\(S \)石の小さな山の正確数が一定値石のすべての現在の数の石の小さな山の数を維持するために、バレルのを、最初の範囲が空である\(0 \)

石の山のために、その数を超えない(N / S = \ mathcal \ \ O(\ SQRT {N})) 、直接計算することができます。

情報も中にモザンビークつ以上のチームであってもよい\(\ mathcal O(1) \) のみのお問い合わせに対処する上で計算される維持します。

前処理階乗階乗逆元、質問はスタック、暴力の小石の山の対応する数によって、計算のために石や砂利の対応する数に各回答について計算されたときにタブを横断します。

時間計算量は\(\ mathcal O(N \ SQRT {Q} + Q \ SQRT {N})\)

#include <cstdio>
#include <cmath>
#include <algorithm>

typedef long long LL;
const int Mod = 998244353;
const int MN = 100005, MQ = 100005, MS = 325;

inline int qPow(int b, int e) {
    int a = 1;
    for (; e; e >>= 1, b = (LL)b * b % Mod)
        if (e & 1) a = (LL)a * b % Mod;
    return a;
}

int Fac[MN], iFac[MN];
void Init(int N) {
    Fac[0] = 1;
    for (int i = 1; i <= N; ++i) Fac[i] = (LL)Fac[i - 1] * i % Mod;
    iFac[N] = qPow(Fac[N], Mod - 2);
    for (int i = N; i >= 1; --i) iFac[i - 1] = (LL)iFac[i] * i % Mod;
}
inline int Binom(int N, int M) {
    if (M < 0 || M > N) return 0;
    return (LL)Fac[N] * iFac[M] % Mod * iFac[N - M] % Mod;
}

int N, S, blk[MN], A[MN], B[MN], D[MN], C;
int Q, ql[MQ], qr[MQ], qp[MQ], Ans[MQ];
int vis[MN], buk[MS], seq[MN], cnt, SG;
inline void Mdf(int x, int t) {
    SG ^= vis[x];
    if (B[x] < S) {
        --buk[vis[x]];
        vis[x] += t;
        ++buk[vis[x]];
    } else vis[x] += t;
    SG ^= vis[x];
}
inline int Num(int x) { return Binom(x, x ^ SG); }

int main() {
    Init(100000);
    int Tests;
    scanf("%d", &Tests);
    while (Tests--) {
        scanf("%d", &N), SG = cnt = C = 0, S = sqrt(N);
        for (int i = 1; i <= N; ++i) scanf("%d", &A[i]), D[++C] = A[i];
        std::sort(D + 1, D + C + 1), C = std::unique(D + 1, D + C + 1) - D - 1;
        for (int i = 1; i <= C; ++i) vis[i] = B[i] = 0;
        for (int i = 1; i <= N; ++i) ++B[A[i] = std::lower_bound(D + 1, D + C + 1, A[i]) - D];
        for (int i = 1; i <= C; ++i) if (B[i] >= S) seq[++cnt] = i;
        for (int i = 1; i <= N; ++i) blk[i] = (i - 1) / S + 1;
        for (int i = 1; i < S; ++i) buk[i] = 0;
        scanf("%d", &Q);
        for (int i = 1; i <= Q; ++i) scanf("%d%d", &ql[i], &qr[i]), qp[i] = i, Ans[i] = 0;
        std::sort(qp + 1, qp + Q + 1, [](int i, int j) {
            if (blk[ql[i]] == blk[ql[j]])
                return blk[ql[i]] & 1 ? qr[i] < qr[j] : qr[i] > qr[j];
            return blk[ql[i]] < blk[ql[j]];
        });
        int L = 1, R = 0;
        for (int I = 1; I <= Q; ++I) {
            int i = qp[I], l = ql[i], r = qr[i];
            while (L > l) Mdf(A[--L], 1);
            while (R < r) Mdf(A[++R], 1);
            while (L < l) Mdf(A[L++], -1);
            while (R > r) Mdf(A[R--], -1);
            if (!SG) { Ans[i] = 0; continue; }
            for (int j = 1; j < S; ++j) Ans[i] = (Ans[i] + (LL)buk[j] * Num(j)) % Mod;
            for (int j = 1; j <= cnt; ++j) Ans[i] = (Ans[i] + Num(vis[seq[j]])) % Mod;
        }
        for (int i = 1; i <= Q; ++i) printf("%d\n", Ans[i]);
    }
    return 0;
}

INVXOR

我々はそれの計算方法を知っているシーケンスを検討し、かなりの範囲を

不完全このビット上の配列の全てが、ある場合プレスビットが、考えられている\(0 \) 次にである(1 \)\位置は、任意に決定結果とすることができるの寄与ので\(2 ^ {N --1} \) ビットのビット値を乗じました。

素人の観点で、そうシーケンス番号のすべてが\(\ mathrm}または{\) またはビット)である(X \)\美しい度\(2 ^ {N - 1 } \ CDOT X \) 。

だから、順番に、計算方法を美しい範囲\(B \)シーケンスの数?これは、計算され(F(N、B)\)\

まず、場合\(Bは\)ではない(2 ^ {N - 1 \ } \) の複数の\(F(N、B) \) である\(0 \)

そうでない場合せる\(= X-B / N 2 ^ { - }。1 \) 次いで、\({または} \ \ mathrm ) 値について\(X- \) 場合\(N \)数が最大に等しいか(\ X-は\)どのような条件が満たされていますか?

ため\(X- \)である\(1 \)ビット、異なるビット互いに独立して、各ビットのプログラム番号( - 1)\(2 ^ {N})\

ためのプログラムの総数ので\({(2 ^ N - 1)} ^ {\ mathrm {POPCOUNT}(X-)} \) すなわち\(F(N、B) = {(2 ^ N - 1)} ^ {\ mathrm POPCOUNT} {(X-)} \)

表題所与\(F(N、B)\ X-当\ PMOD {M} \) および最小必要\(Bを\)

オーダー\(K = \ mathrm {POPCOUNT}(X-)\) 次いで\(K \)前提が取る決定(X = 2 ^ K - \ 1 \)が可能\(X- \)最小値を、さらにてみましょう\(B \)最小。

だから、最低限考える\(K \)ライン上を。

方程式の解は、次にある- (^ K \ X-当\ PMOD {M} \ {1)。(2 ^ N})\、標準的な離散対数問題であり、使用することができExBSGSアルゴリズム。

溶液は、持っていた\(K \) 対応する\(B \)のように\({ - }。1(2 ^ K - 。N 2 ^ 1)\) その後終了します。

ので\(Nは\)整数精度であるので、考慮すべきそのモジュロ時間のディスクリートソリューションの数に演算を行う\(M \)モジュロ演算子への答え(998244353 \)\テイクモード。

しかし、問題は、これらのピットである\(Bが\)ではない\(2 ^ {N - 1 } \) の複数の\(F(N、B)= 0 \) このような状況を考慮する必要がありますA。

場合\(N \ GE 2 \)\(X = 0 \)\(M \ GE 2 \)このような状況が発生すると、出力が必要\(1 \)

#include <cstdio>
#include <cstring>
#include <cmath>
#include <unordered_map>

typedef long long LL;
const int Mod = 998244353, Inv2 = (Mod + 1) / 2;

inline int qPow(int b, int e) {
    int a = 1;
    for (; e; e >>= 1, b = (LL)b * b % Mod)
        if (e & 1) a = (LL)a * b % Mod;
    return a;
}

int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
int exgcd(int a, int b, int &x, int &y) {
    if (!b) return x = 1, y = 0, a;
    int d = exgcd(b, a % b, y, x);
    return y -= a / b * x, d;
}

std::unordered_map<int, int> buk;
inline int BSGS(int a, int b, int m) {
    int S = sqrt(m - 1) + 1;
    int A = 1, f = -1;
    buk.clear();
    for (int i = 0; i < S; ++i) {
        buk[(LL)b * A % m] = i;
        A = (LL)A * a % m;
    }
    int C = 1;
    for (int i = 1; !~f && i <= S; ++i)
        if (buk.count(C = (LL)C * A % m))
            f = i * S - buk[C];
    return f;
}

inline int ExBSGS(int a, int b, int m) {
    int o = 0, A = 1 % m, d = 1, nd, x, y;
    while (1) {
        if (d == (nd = gcd((LL)A * a % m, m))) break;
        if (A == b) return o;
        ++o, A = (LL)A * a % m, d = nd;
    }
    if (b % d) return -1;
    m /= d, b /= d, A /= d;
    exgcd(A, m, x, y);
    b = (LL)b * (x + m) % m;
    x = b == 1 % m ? 0 : BSGS(a, b, m);
    if (!~x) return -1;
    return o + x;
}

const int MS = 10005;
char S[MS];
int A[MS], Len, X, M;
int pw2[10];

inline void Init() {
    scanf("%s%d%d", S + 1, &X, &M), Len = strlen(S + 1);
    for (int i = 1; i <= Len; ++i) A[i] = S[i] - '0';
    pw2[0] = 1 % M;
    for (int i = 1; i < 10; ++i) pw2[i] = pw2[i - 1] * 2 % M;
}

int main() {
    int Tests;
    scanf("%d", &Tests);
    while (Tests--) {
        Init();
        if (X == 1 % M) { puts("0"); continue; }
        if (X == 0 && (Len >= 2 || A[1] >= 2)) { puts("1"); continue; }
        int V = 1 % M;
        for (int i = 1; i <= Len; ++i) {
            int _2 = (LL)V * V % M;
            int _5 = (LL)_2 * _2 % M * V % M;
            V = (LL)_5 * _5 % M * pw2[A[i]] % M;
        }
        V = (V ? V : M) - 1;
        int K = ExBSGS(V, X, M);
        if (!~K) { puts("-1"); continue; }
        int Ans = 1;
        for (int i = 1; i <= Len; ++i) {
            int _2 = (LL)Ans * Ans % Mod;
            int _5 = (LL)_2 * _2 % Mod * Ans % Mod;
            Ans = (((LL)_5 * _5 % Mod) << A[i]) % Mod;
        }
        printf("%lld\n", (LL)Ans * Inv2 % Mod * (qPow(2, K) - 1) % Mod);
    }
    return 0;
}

EGGFREE

櫛タイトル面は、無向要件を指向エッジ、DAGは、NOの存在するようにされていない\(Yに対してX \ \)\(ZにX \ \)が、\(Y、Z \)の縁との間に接続されていません。

だから、当然、私たちも、エッジにポイントトポロジカル順序の後の最初のポイントを強制的にシーケンストポロジー、トポロジーの順番を考えます。

この制限は、偶数偶数グループを形成する点まで、次に、ポイント後方エッジを考慮する、と言うことです。

これは、裸のサイノグラム判断、シーケンスを排除するのに最適な構造であり、ボードの最大の潜在的なアルゴリズムの1を計上し、それは(私は今売らオフよ、あなたを教えてくれません)行われています。

#include <cstdio>
#include <vector>

const int MN = 200005, MM = 200005;

int N, M, eu[MM], ev[MM];
std::vector<int> G[MN], V[MN];
int deg[MN], id[MN], seq[MN], cnt;
int pre[MN], col[MN];

int main() {
    int Tests;
    scanf("%d", &Tests);
    while (Tests--) {
        scanf("%d%d", &N, &M);
        for (int i = 1; i <= N; ++i) G[i].clear(), deg[i] = id[i] = 0;
        for (int i = 1; i <= M; ++i)
            scanf("%d%d", &eu[i], &ev[i]),
            G[eu[i]].push_back(ev[i]),
            G[ev[i]].push_back(eu[i]);
        for (int i = 0; i < N; ++i) V[i].clear();
        for (int i = 1; i <= N; ++i) V[0].push_back(i);
        int best = 0;
        for (int i = 1, u; i <= N; ++i, ++best) {
            while (V[best].empty() || id[V[best].back()])
                if (V[best].empty()) --best;
                else V[best].pop_back();
            id[seq[i] = u = V[best].back()] = i;
            for (int v : G[u]) if (!id[v]) V[++deg[v]].push_back(v);
        }
        for (int i = 1; i <= N; ++i) V[i].clear();
        for (int i = 1; i <= N; ++i) {
            pre[i] = 0;
            for (int u : G[i]) if (id[u] < id[i])
                if (id[pre[i]] < id[u]) pre[i] = u;
            if (!pre[i]) continue;
            for (int u : G[i]) if (id[u] < id[i])
                if (u != pre[i]) V[pre[i]].push_back(u);
        }
        int ok = 1;
        for (int i = 1; i <= N; ++i) {
            int u = seq[i];
            for (int v : G[u]) col[v] = u;
            for (int v : V[u]) if (col[v] != u) ok = 0;
        }
        if (!ok) { puts("No solution"); continue; }
        for (int i = 1; i <= M; ++i) putchar(id[eu[i]] < id[ev[i]] ? 'v' : '^');
        putchar('\n');
    }
    return 0;
}

ブレーク

最初のサブタスクは、ラウンド中にすべてのカードを完了します。

最高の意思決定の反対側に再生されます最低のカードを見つけるために導出ルックはの間、あなたのアカウントにあなたは基礎を再生することができます(厳密に)必要な第2の小さなカードを取りたいので(最低カードに対処することですが、中ブランドも)戦わなければなりませんでした。

だから、長い行A列として、その後、ライン上で再生する場合、各カードが合法であるかを決定。

第2のサブタスクは、私がここでの問題への公式のソリューションを与えられたコードを書く、とほとんど一致私の推測のいくつか実際には、結論が最後の言葉だと思いませんでした。

  • 以下のための(N \ル2 \)\場合公報判決。
  • ブランドがあればより多く表示されます(N \)\たびに異なる2枚のカードが失われ、その答えがあるので、倍(、半分以上です)NO
  • すべてのカードが同じである、と自分の体重は、他のすべてのカード(または同等)よりも大きい場合の答えがあるので、その後、いったん破棄されたどのように多くのカードに関係なく、ノー法の攻防変換するのでお互いを与えますNO
  • 他のすべてのカードが同じ重さと任意の自分の手よりも小さい(または同等のもの)である場合、答えはNO、同上。
  • 答えは他のすべての例YES(理由を知りません)。

\(50 \)コードポイント:

#include <cstdio>
#include <algorithm>

const int MN = 100005;

int N, A[MN], B[MN], D[MN * 2], C;

inline void Z(int *Ar) {
    for (int i = 1, j = 1; i <= N; ++i) {
        while (j < C && D[j] < Ar[i]) ++j;
        Ar[i] = j;
    }
}
inline void Init() {
    scanf("%d", &N);
    for (int i = 1; i <= N; ++i) scanf("%d", &A[i]);
    for (int i = 1; i <= N; ++i) scanf("%d", &B[i]);
    std::sort(A + 1, A + N + 1), std::sort(B + 1, B + N + 1);
    std::merge(A + 1, A + N + 1, B + 1, B + N + 1, D + 1);
    C = std::unique(D + 1, D + 2 * N + 1) - D - 1, Z(A), Z(B);
}

int buk[MN * 2];
inline int check() {
    for (int i = 1; i <= N; ++i) if (A[i] >= B[i]) return 0;
    for (int i = 1; i <= C; ++i) buk[i] = 0;
    for (int i = 1; i < N; ++i) {
        buk[A[i]] = buk[B[i]] = 1;
        if (!buk[A[i + 1]]) return 0;
    }
    return 1;
}

int main() {
    int Tests, Type;
    scanf("%d%d", &Tests, &Type);
    while (Tests--) {
        Init();
        int Ans = check();
        if (Ans) { puts("YES"); continue; }
        if (Type == 1) { puts("NO"); continue; }
//      printf("\t\tA : "); for (int i = 1; i <= N; ++i) printf("%d, ", A[i]); puts("");
//      printf("\t\tB : "); for (int i = 1; i <= N; ++i) printf("%d, ", B[i]); puts("");
    }
    return 0;
}

GOODSEGS

スケーラビリティの単調+スタック・セグメントツリーを実践し、最近3つだけの慣行まで問題の連続配列セグメントは、最強です。

しかし、劉チェンオーストリアの発明により、ツリー近くの分析は、さらに高いレベルに抽象ツリー構造の連続セグメントの問題を作るために一緒に、分析をこのような状況を打破することが判明しました。

あなたが一緒に馴染みの木解析している場合、我々は、2つの連続セグメントの交差点を見つけることができますが、含まれていません(\ [A、B] \ ) と\([C、D] \)(\ (A <C \ルB <D \) の3つのセクションが単離された\) - ([1、C] \ \ )([C、B] \ \ )\、[、D 1 B +。(連続部分であるが、それらは必要フィットポイント子供のを命じました。

我々は、次に、それぞれの子係ポイントのポインタの一対のスキャンは、そう決定することができるの中央\([C、B] \ ) に等しいよりも長さも大きいのに対して\(X- \) 限り実行プログラムのいくつかの側面についてのそれらのプログラム簡単な数学的変換をすることができます。

のみ胡口なので、ツリー解析を一緒に書いていない、理解はグーのコードので、徹底的ではありません。

関心のある読者は自分で行くことができOIウィキ-解析一緒にツリー検査。

ADANTS

チャレンジは、分析を行いません。

おすすめ

転載: www.cnblogs.com/PinkRabbit/p/CCMARCH20A.html