LOJ 510: "LibreOJ NOIラウンド#1" 北の学校の思い出外

トピックポータル:LOJ#510

質問の意味の説明:

与えられた\(K \)進数でフェンウィックツリーが、その実装が問題です。

正式前記ので(\ mathrm {lowbit}(\ \ X)) として(K \)\進数で(X \)\、例えば、最小非ゼロのビット値である(\ mathrm {lowbit} \ \!\左(230 _ {(5)} \右)\!_ = {30(5)} \)

add(x, v)操作が行われた:
とき\(X \ルN \) 実行s[x] ^= v、および\(Xは\)になる\(X + \ mathrm lowbit} {(X)\) サイクルが継続します。

query(x)操作が実行される:
注文\(ANS \)初期値の\(0 \)
場合\(X> 0 \) 実行ans ^= s[x]、および\(X \)となる\(X - \ mathrm lowbit} {(X)\) そしてサイクルが継続します。
最終的に返される\(ANS \)

ソリューション:

正しく書き込まれ、異なりadd回数が動作中に実行されない\(\ mathcal O(K \ log_K N)\) が、\(\ mathcal O(N) \) が発生したときに観察された複雑さ変更:
ときは、(K = 3、X = 1 \)\ 時間、\(X \) \:(10進数)に変更し、\ 2 \ 1(4 \ 5 \ 7 \ 8 \ 10。。。。。 \へ\ cdots \)

見つけることができ、\(X- \)\(K \)バイナリで最も低い非ゼロのビット位置は変更されないまま、とにビットの最小非ゼロ値\(1、2、1、 2、\ ldots \ サイクル。

異なるため\(K \) 我々は、指定された最小の非ゼロのビットの値の変化を観察し、いくつかは最終的になって見つける\(0 \) それはもはやゼロであること、他の人が落下しながらループ。

明らかに、これは実際には関数である\(F(X)= 2X \ BMOD K \) の構成要素を接続ルートである、フォレスト内の環である対応するグラフ上の転送処理\(0 \ 0 \)にリングから、および\(0 \) 最終的に非ゼロの数字を強化する最低点に接続されています。

数論は、ツリーリング内のそれらのそれぞれの深さは超えないことを教えてくれる\(\ log_2 Kを\)ルートである場合ところ、\(0 \)ツリー内のベースリングの、最低レベルのみが変更されます(\ \ log_Kのn \)の合計数と、\(\ log_2 K \回\ log_K N- = \ log_2 \ N-)あなたは暴力のこの部分をスキップすることができますので、。

最後にそれはない落ちたとき\(0 \)の場合の環は、上記の例を参照して、後方に延びる無限鎖を形成することになるが、それはチェーンループ部の隣接位置間が差です。
プリアウト各鎖の場合は、接尾辞、単一の列挙動作を維持するために、各チェーンのツリー配列を開始することができます。
しかしながら、この範囲は、直接前処理は大きすぎるので、即ち、鎖に直接決定ポイントの数を乗算する方法を考える\(X \) 現在の位置にいくつかのチェーンの最初のものである、直接であってもよいですフェンウィックツリー動作(もちろん、この時間範囲は依然として大きいが、位置の変化のハッシュにより小さなアレイにマッピングされます)。

同じトークンを、尋ねられたときqueryとき\(X \)に変更します\(\ log_K N \)あなたが最初に決定し、調査を指示することができますので、回、毎回(X \)\チェーン上で直接修正しない場合、(\ ANS \) またはサフィックスに改訂対応前(動作の一本鎖列挙を対応する電流フェンウィックツリー上に存在する必要がある)、差が、プレフィックスがチェック追加の一点になることができ、古典でありますハッシュに広い範囲の共感方法のフェンウィックツリー動作。

ここで、コードは、ハッシュの時間複雑さを仮定すると、である\(\ mathcal O(1)\) 次いで合計時間複雑である\(\ mathcal O(K \ログN + Q \ log_K N \)Nログ\) :

#include <cstdio>

const int HASH = 19260817, NUMS = 10000005;
int h[HASH], nxt[NUMS], to[NUMS], tot;
inline int Hasher(int val, int typ) {
    int cyp = (val ^ val >> 1) % HASH;
    for (int i = h[cyp]; i; i = nxt[i]) if (to[i] == val) return i;
    return typ ? nxt[++tot] = h[cyp], to[tot] = val, h[cyp] = tot : 0;
}

typedef long long LL;
const int MK = 200005;

int N, K, Q, V[6], C;
inline void lowbit(int x, int &y, int &z) {
    int s = 1, t = C;
    while (t) { if (x % V[t] == 0) x /= V[t], s *= V[t]; --t; }
    y = x % K, z = y * s;
}
int ltrs[MK][30], ntrs[MK][30];
LL lsum[MK][30], nsum[MK][30];
int arr[NUMS];

int main() {
    scanf("%d%d%d", &N, &Q, &K);
    for (LL x = K; x <= N; x *= x) V[++C] = x;
    for (int i = 1; i < K; ++i) if ((i & -i) >= (K & -K))
        ltrs[i * 2 % K][0] = lsum[i * 2 % K][0] = i,
        ntrs[i][0] = i * 2 % K, nsum[i][0] = i;
    for (int j = 0; j < 29; ++j)
        for (int i = 1; i < K; ++i) if ((i & -i) >= (K & -K))
            ltrs[i][j + 1] = ltrs[ltrs[i][j]][j],
            lsum[i][j + 1] = lsum[i][j] + lsum[ltrs[i][j]][j],
            ntrs[i][j + 1] = ntrs[ntrs[i][j]][j],
            nsum[i][j + 1] = nsum[i][j] + nsum[ntrs[i][j]][j];
    for (int i = 1; i <= Q; ++i) {
        int op, x, y, z, v, d;
        scanf("%d%d", &op, &x);
        if (op == 1) {
            scanf("%d", &v);
            while (x <= N) {
                lowbit(x, y, z);
                if ((y & -y) >= (K & -K)) {
                    int id = 0, X = x, Y = y, w = z / y;
                    for (int j = 29; j >= 0; --j)
                        if (lsum[Y][j] < X / w)
                            id |= 1 << j,
                            X -= lsum[Y][j] * w,
                            Y = ltrs[Y][j];
                    ++id;
                    for (int j = 0; x <= N; ++j) if (id >> j & 1) {
                        arr[Hasher(x, 1)] ^= v;
                        x += nsum[y][j] * w;
                        y = ntrs[y][j];
                        id += 1 << j;
                    }
                    break;
                }
                arr[Hasher(x, 1)] ^= v;
                x += z;
            }
        } else {
            int Ans = 0;
            while (x) {
                lowbit(x, y, z);
                if ((y & -y) >= (K & -K)) {
                    int id = 0, X = x, Y = y, w = z / y;
                    for (int j = 29; j >= 0; --j)
                        if (lsum[Y][j] < X / w)
                            id |= 1 << j,
                            X -= lsum[Y][j] * w,
                            Y = ltrs[Y][j];
                    ++id;
                    X = x, Y = y;
                    for (int j = 0; id; ++j, id >>= 1) if (id & 1) {
                        if ((d = Hasher(X, 0))) Ans ^= arr[d];
                        X -= lsum[Y][j] * w;
                        Y = ltrs[Y][j];
                    }
                } else if ((d = Hasher(x, 0))) Ans ^= arr[d];
                x -= z;
            }
            printf("%d\n", Ans);
        }
    }
    return 0;
}

おすすめ

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