QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#349783#8335. Fast Hash Transformucup-team2894#TL 4970ms4236kbC++2018.6kb2024-03-10 05:26:482024-03-10 05:26:48

Judging History

你现在查看的是最新测评结果

  • [2024-03-10 05:26:48]
  • 评测
  • 测评结果:TL
  • 用时:4970ms
  • 内存:4236kb
  • [2024-03-10 05:26:48]
  • 提交

answer

#pragma GCC optimize("Ofast")
#pragma GCC target("popcnt")
#include <bits/stdc++.h>
#define fr first
#define sc second
#define all(a) (a).begin(), (a).end()
#define unique(a) a.resize(unique(a.begin(), a.end()) - a.begin())
#define popcnt(x) __builtin_popcountll(x)

using namespace std;

#ifdef ONPC
mt19937 rnd(223);
mt19937 rndll(223);
#else
mt19937 rnd(chrono::high_resolution_clock::now()
			.time_since_epoch().count());
mt19937 rndll(223);
#endif

#define TIME (clock() * 1.0 / CLOCKS_PER_SEC)

using ll = long long;
using ld = double;

const int maxn = 2e4 + 100, inf = 1e9 + 100;


namespace segtree {

// This implementation is disgusting, but it seems to work and do it faster than previous version.

    template<typename Item>
    Item tree_merge(const Item& a, const Item& b) {
        Item i;
        i.update(a, b);
        return i;
    }

    template<typename Item, bool lazy>
    struct Pusher {};

    template<typename Item>
    struct Pusher<Item, false> {
        void push(const vector<Item>&, int, int, int) {}
        Item ask_on_segment(const vector<Item>& tree, int n, int l, int r) {
            l |= n;
            r |= n;
            Item resl, resr;
            while (l <= r) {
                if (l & 1) {
                    resl = tree_merge(resl, tree[l]);
                    ++l;
                }
                if (!(r & 1)) {
                    resr = tree_merge(tree[r], resr);
                    --r;
                }
                l >>= 1;
                r >>= 1;
            }
            return tree_merge(resl, resr);
        }
        void push_point(const vector<Item>&, int, int) {}

        template<typename P>
        int lower_bound(const vector<Item>& tree, int n, int l, P p) {
            Item cur;
            if (p(cur)) return l - 1;
            l |= n;
            int r = n | (n - 1);
            // carefully go up
            while (true) {
                if (p(tree_merge(cur, tree[l]))) {
                    break;
                }
                if (l == r) return n;
                if (l & 1) {
                    cur = tree_merge(cur, tree[l]);
                    ++l;
                }
                l >>= 1;
                r >>= 1;
            }

            // usual descent from l
            while (l < n) {
                if (p(tree_merge(cur, tree[l * 2]))) {
                    l = l * 2;
                } else {
                    cur = tree_merge(cur, tree[l * 2]);
                    l = l * 2 + 1;
                }
            }
            return (l ^ n);
        }

        template<typename P>
        int lower_bound_rev(const vector<Item>& tree, int n, int r, P p) {
            Item cur;
            if (p(cur)) return r + 1;
            r |= n;
            int l = n;
            // carefully go up
            while (true) {
                if (p(tree_merge(tree[r], cur))) {
                    break;
                }
                if (l == r) return -1;
                if (!(r & 1)) {
                    cur = tree_merge(tree[r], cur);
                    --r;
                }
                l >>= 1;
                r >>= 1;
            }

            // usual descent from r
            while (r < n) {
                if (p(tree_merge(tree[r * 2 + 1], cur))) {
                    r = r * 2 + 1;
                } else {
                    cur = tree_merge(tree[r * 2 + 1], cur);
                    r = r * 2;
                }
            }
            return (r ^ n);
        }
    };

    template<typename Item>
    struct Pusher<Item, true> {
        void push(vector<Item>& tree, int ind, int l, int r) {
            tree[ind].push(tree[ind * 2], tree[ind * 2 + 1], l, r);
        }

        Item ask_on_segment(vector<Item>& tree, int n, int l, int r) {
            int vl = 0, vr = n - 1;
            int i = 1;
            Item result;
            while (vl != vr) {
                int m = (vl + vr) / 2;
                if (l > m) {
                    push(tree, i, vl, vr);
                    i = i * 2 + 1;
                    vl = m + 1;
                } else if (r <= m) {
                    push(tree, i, vl, vr);
                    i = i * 2;
                    vr = m;
                } else {
                    break;
                }
            }
            if (l == vl && r == vr) {
                return tree[i];
            }
            push(tree, i, vl, vr);
            // left
            {
                int ind = i * 2;
                int L = vl, R = (vl + vr) / 2;
                while (l != L) {
                    int m = (L + R) / 2;
                    push(tree, ind, L, R);
                    if (l <= m) {
                        result = tree_merge(tree[ind * 2 + 1], result);
                        ind *= 2;
                        R = m;
                    } else {
                        ind = ind * 2 + 1;
                        L = m + 1;
                    }
                }
                result = tree_merge(tree[ind], result);
            }
            // right
            {
                int ind = i * 2 + 1;
                int L = (vl + vr) / 2 + 1, R = vr;
                while (r != R) {
                    int m = (L + R) / 2;
                    push(tree, ind, L, R);
                    if (r > m) {
                        result = tree_merge(result, tree[ind * 2]);
                        ind = ind * 2 + 1;
                        L = m + 1;
                    } else {
                        ind = ind * 2;
                        R = m;
                    }
                }
                result = tree_merge(result, tree[ind]);
            }
            return result;
        }

        void push_point(vector<Item>& tree, int n, int ind) {
            int l = 0, r = n - 1;
            int i = 1;
            while (l != r) {
                push(tree, i, l, r);
                int m = (l + r) / 2;
                if (ind <= m) {
                    r = m;
                    i *= 2;
                } else {
                    l = m + 1;
                    i = i * 2 + 1;
                }
            }
        }

        template<typename P>
        pair<int, Item> _lower_bound(vector<Item>& tree, int l, P p, Item cur, int i, int vl, int vr) {
            if (vl == vr) {
                if (p(tree_merge(cur, tree[i]))) {
                    return {vl, tree[i]};
                } else {
                    return {vl + 1, tree[i]};
                }
            }

            push(tree, i, vl, vr);
            int m = (vl + vr) / 2;
            if (l > m) {
                return _lower_bound(tree, l, p, cur, i * 2 + 1, m + 1, vr);
            } else if (l <= vl) {
                if (!p(tree_merge(cur, tree[i]))) {
                    return {vr + 1, tree_merge(cur, tree[i])};
                }
                if (p(tree_merge(cur, tree[i * 2]))) {
                    return _lower_bound(tree, l, p, cur, i * 2, vl, m);
                } else {
                    return _lower_bound(tree, l, p, tree_merge(cur, tree[i * 2]), i * 2 + 1, m + 1, vr);
                }
            } else {
                auto [ind, it] = _lower_bound(tree, l, p, cur, i * 2, vl, m);
                if (ind <= m) return {ind, it};
                return _lower_bound(tree, l, p, it, i * 2 + 1, m + 1, vr);
            }
        }

        template<typename P>
        int lower_bound(vector<Item>& tree, int n, int l, P p) {
            Item cur;
            if (p(cur)) return l - 1;
            return _lower_bound(tree, l, p, cur, 1, 0, n - 1).first;
        }

        template<typename P>
        pair<int, Item> _lower_bound_rev(vector<Item>& tree, int r, P p, Item cur, int i, int vl, int vr) {
            if (vl == vr) {
                if (p(tree_merge(tree[i], cur))) {
                    return {vl, tree[i]};
                } else {
                    return {vl - 1, tree[i]};
                }
            }

            push(tree, i, vl, vr);
            int m = (vl + vr) / 2;
            if (r <= m) {
                return _lower_bound_rev(tree, r, p, cur, i * 2, vl, m);
            } else if (r >= vr) {
                if (!p(tree_merge(tree[i], cur))) {
                    return {vl - 1, tree_merge(cur, tree[i])};
                }
                if (p(tree_merge(tree[i * 2 + 1], cur))) {
                    return _lower_bound_rev(tree, r, p, cur, i * 2 + 1, m + 1, vr);
                } else {
                    return _lower_bound_rev(tree, r, p, tree_merge(tree[i * 2 + 1], cur), i * 2, vl, m);
                }
            } else {
                auto [ind, it] = _lower_bound_rev(tree, r, p, cur, i * 2 + 1, m + 1, vr);
                if (ind > m) return {ind, it};
                return _lower_bound_rev(tree, r, p, it, i * 2, vl, m);
            }
        }

        template<typename P>
        int lower_bound_rev(vector<Item>& tree, int n, int r, P p) {
            Item cur;
            if (p(cur)) return r + 1;
            return _lower_bound_rev(tree, r, p, cur, 1, 0, n - 1).first;
        }
    };

    template<typename Item, bool lazy = false>
    struct Segtree {
        vector<Item> tree;
        Pusher<Item, lazy> pusher;
        int n;
        int n0;

        Segtree(int n = 0) {
            build(n);
        }

        template<typename U>
        Segtree(const vector<U>& v) {
            build(v);
        }

        void build(int n) {
            this->n0 = n;
            while (n & (n - 1)) ++n;
            this->n = n;
            tree.assign(n * 2, {});
        }

        template<typename U>
        void build(const vector<U>& v) {
            build(v.size());
            for (int i = 0; i < v.size(); ++i) {
                tree[n | i].init(v[i], i);
            }
            build();
        }

        void build() {
            for (int i = n - 1; i >= 1; --i) {
                tree[i].update(tree[i * 2], tree[i * 2 + 1]);
            }
        }

        void push(int ind, int l, int r) {
            pusher.push(tree, ind, l, r);
        }

        template<typename T>
        void set(int ind, const T& t) {
            pusher.push_point(tree, n, ind);
            ind |= n;
            tree[ind].init(t, ind ^ n);
            ind >>= 1;
            while (ind) {
                tree[ind].update(tree[ind * 2], tree[ind * 2 + 1]);
                ind >>= 1;
            }
        }

        template<typename T>
        void update(int ind, const T& t) {
            pusher.push_point(tree, n, ind);
            ind |= n;
            tree[ind].update(t, ind ^ n);
            ind >>= 1;
            while (ind) {
                tree[ind].update(tree[ind * 2], tree[ind * 2 + 1]);
                ind >>= 1;
            }
        }

        Item& ith(int ind) {
            static_assert(!lazy, "don't use this method with lazy propagation, unless you're sure you need it");
            return tree[ind | n];
        }

        const Item& root() const {
            return tree[1];
        }

        Item ask(int l, int r) {
            l = max(l, 0);
            r = min(r, n - 1);
            if (l > r) return {};
            return pusher.ask_on_segment(tree, n, l, r);
        }

        template<typename T>
        void modify(int l, int r, const T& t) {
            static_assert(lazy, "lazy must be set to true to use this function");
            l = max(l, 0);
            r = min(r, n - 1);
            if (l > r) return;
            int vl = 0, vr = n - 1;
            int i = 1;
            while (vl != vr) {
                int m = (vl + vr) / 2;
                if (l > m) {
                    push(i, vl, vr);
                    i = i * 2 + 1;
                    vl = m + 1;
                } else if (r <= m) {
                    push(i, vl, vr);
                    i = i * 2;
                    vr = m;
                } else {
                    break;
                }
            }
            if (l == vl && r == vr) {
                tree[i].modify(t, l, r);
            } else {
                push(i, vl, vr);
                // left
                {
                    int ind = i * 2;
                    int L = vl, R = (vl + vr) / 2;
                    while (l != L) {
                        int m = (L + R) / 2;
                        push(ind, L, R);
                        if (l <= m) {
                            tree[ind * 2 + 1].modify(t, m + 1, R);
                            ind *= 2;
                            R = m;
                        } else {
                            ind = ind * 2 + 1;
                            L = m + 1;
                        }
                    }
                    tree[ind].modify(t, L, R);
                    ind >>= 1;
                    while (ind != i) {
                        tree[ind].update(tree[ind * 2], tree[ind * 2 + 1]);
                        ind >>= 1;
                    }
                }
                // right
                {
                    int ind = i * 2 + 1;
                    int L = (vl + vr) / 2 + 1, R = vr;
                    while (r != R) {
                        int m = (L + R) / 2;
                        push(ind, L, R);
                        if (r > m) {
                            tree[ind * 2].modify(t, L, m);
                            ind = ind * 2 + 1;
                            L = m + 1;
                        } else {
                            ind = ind * 2;
                            R = m;
                        }
                    }
                    tree[ind].modify(t, L, R);
                    ind >>= 1;
                    while (ind != i) {
                        tree[ind].update(tree[ind * 2], tree[ind * 2 + 1]);
                        ind >>= 1;
                    }
                }
                tree[i].update(tree[i * 2], tree[i * 2 + 1]);
            }
            i >>= 1;
            while (i) {
                tree[i].update(tree[i * 2], tree[i * 2 + 1]);
                i >>= 1;
            }
        }

        // first index r such that p(tree.ask(l, r)) == true
        // if p() is true for empty item, return l-1
        // if p() is never true, returns n
        template<typename P>
        int lower_bound(int l, P p) {
            l = max(l, 0);
            if (l >= n0) return n0;
            return min(n0, pusher.lower_bound(tree, n, l, p));
        }

        // similarly to lower_bound, returns first (largest) l such that p(tree.ask(l, r)) == true
        template<typename P>
        int lower_bound_rev(int r, P p) {
            r = min(r, n0 - 1);
            if (r < 0) return -1;
            return pusher.lower_bound_rev(tree, n, r, p);
        }
    };

}
using segtree::Segtree;

#define uint oleg
using uint = uint64_t;

using Mat = array<uint, 64>;

const uint one = 1;

inline bool mult(uint x, uint y) {
    return popcnt(x & y) & 1;
}

struct Li {
    Mat a{};
    uint b{};

    void upd(int i, int j, bool w) {
        if (w)
            a[j] ^= (one << i);
    }

    uint apply(uint x) const {
        uint w = 0;
        for (int i = 0; i < 64; i++)
            if (mult(x, a[i]))
                w ^= (one << i);
        return w ^ b;
    }
};

Li def() {
    Li q{};
    for (int i = 0; i < 64; i++)
        q.upd(i, i, 1);
    return q;
}

Mat c{};

Li comb(Li const &x, Li const &y) {
    c = {};
    Li q{};
    for (int i = 0; i < 64; i++)
        for (int j = 0; j < 64; j++)
            if (x.a[j] & (one << i))
                c[i] ^= (one << j);
    for (int i = 0; i < 64; i++)
        for (int j = 0; j < 64; j++)
            q.upd(i, j, mult(c[i], y.a[j]));
    q.b = y.apply(x.b);
    return q;
}

Li a[maxn];

#define cin if(1)cin

Li read_hash() {
    int m = 64;
    cin >> m;
    Li q;
    for (int it = 0; it < m; it++) {
        int s = it, o = rnd() & 1;
        uint A = rndll();
        cin >> s >> o >> A;
        if (o == 0) {
            // or
            for (int i = 0; i < 64; i++)
                if (A & (one << i)) {
                    q.b ^= (one << i);
                }
            A = ~A;
        }
        {
            // and
            for (int i = 0; i < 64; i++) {
                int pe = (i + s) % 64;
                q.upd(i, pe, (A >> pe) & 1);
            }
        }
    }
    uint b;
    cin >> b;
    q.b ^= b;
//    for (int j = 0; j < 64; j++)
//        cerr << q.a[j] << '\n';
//    cerr << q.b << '\n';
//    cerr << "-----------------\n";
    return q;
}

struct Item {
    Li w = def();
    template<typename T>
    void init(const T& t, int ind) {
        w = t;
    }

    void update(const Item& a, const Item& b) {
        w = comb(a.w, b.w);
    }

    //// similar to init, but more convenient for doing a[i] += x, implement only if needed
    // template<typename T>
    // void update(const T& t, int ind) {}

    //// apply here, save for children
    // template<typename T>
    // void modify(const T& m, int l, int r) {}

    // void push(Item& a, Item& b, int l, int r) {
    //     int m = (l + r) / 2;
    //     a.modify(mod, l, m);
    //     b.modify(mod, m + 1, r);
    //     // reset mod
    // }
};

void solve() {
    int n, zaps, C;
    n = zaps = 20000;
    C = 1;
    cin >> n >> zaps >> C;
    vector<Li> a(n);
    for (int i = 0; i < n; i++) {
        a[i] = read_hash();
    }
    cerr << "\n\nreading " << TIME << endl;
    Segtree<Item> t(a);
    cerr << "\n\nbuilding " << TIME << endl;
    while (zaps--) {
        int tp;
        tp = rnd() & 1;
//        tp = 0;
        cin >> tp;
        if (tp == 0) {
            int l, r;
            l = rnd() % n + 1;
            r = rnd() % n + 1;
            if (l > r)
                swap(l, r);
            uint x = rndll();
            cin >> l >> r >> x;
            l--;
            r--;
//            Li z = def();
//            for (int i = l; i <= r; i++)
//                z = comb(z, a[i]);
            x = t.ask(l, r).w.apply(x);
            cout << x << '\n';
        } else {
            int i;
            i = rnd() % n + 1;
            cin >> i;
            i--;
            a[i] = read_hash();
            t.set(i, a[i]);
        }
    }
}

int main() {
#ifdef ONPC
    freopen("../a.in", "r", stdin);
    freopen("../a.out", "w", stdout);
#endif
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout << fixed;
    cout.precision(20);
    solve();
    cerr << "\n\nConsumed " << TIME << endl;
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 1ms
memory: 3932kb

input:

3 5 1
1 4 0 0 51966
1 60 0 0 0
1 0 0 16 15
0 1 1 771
0 2 2 32368
0 3 3 0
1 2 2 0 0 15 61 1 4095 46681
0 1 3 2023

output:

64206
2023
31
1112

result:

ok 4 tokens

Test #2:

score: 0
Accepted
time: 2ms
memory: 3964kb

input:

9 9 3
32 9 0 17785061119123981789 33 0 10890571864137198682 42 0 9437574736788763477 34 0 5239651887868507470 55 0 14741743279679654187 27 1 1444116632918569317 38 1 5740886562180922636 1 1 8113356142324084796 3 0 10955266306442425904 60 0 16421026339459788005 53 0 1595107134632608917 48 1 923204972...

output:

9487331362121050549
3906661590723083106
15757672015979182109
4975471776251039345
11503109206538591140
3763610618439604410

result:

ok 6 tokens

Test #3:

score: 0
Accepted
time: 192ms
memory: 3880kb

input:

1 20000 400
32 13 0 1721926083061553294 52 1 8951352260297008058 6 0 3180917732545757991 63 1 14978562500072226750 50 1 7331113732303115313 59 0 688182721924779475 12 0 16291922173168822489 61 0 16018198440613086698 8 0 12494084957448674305 7 0 2834422858291562646 42 1 10354539547309738529 28 0 2541...

output:

11827781865759498816
7454610526276185721
9581050724293785387
2177163806257271094
14004004964877510141
18073834598135159471
16966489063087641088
12289032565388413023
17823140805867698239
18104549908461644670
15570008264282957124
12400954982104000299
9842549278742638708
16535034933613060362
1561642006...

result:

ok 19600 tokens

Test #4:

score: 0
Accepted
time: 4970ms
memory: 4236kb

input:

500 20000 400
32 3 0 9869926173615303101 39 1 11114680792832491178 54 1 3380955246053990760 31 0 16868042247314276464 26 0 5814925615581342395 30 1 1114053898154397400 46 1 9215698002668459992 38 1 12938485987410997250 58 0 8030873196223549640 0 0 16055471402053138912 47 1 16568729207788187629 63 0 ...

output:

9119093329811149961
16901643057538871933
17161855998497876349
3964234071281411558
13588188063229334268
15557968976322375381
4612345875926431452
9507168112801039022
9504318642653891468
217407202160767706
12982350345598971306
17957502630817476223
6353877977318728572
15552768639781831485
16778108770682...

result:

ok 19600 tokens

Test #5:

score: -100
Time Limit Exceeded

input:

4000 20000 400
35 33 0 18435679328748604368 55 1 10851974578636476759 1 0 11332084644969697080 13 0 4243547822701774011 19 0 18197854269436975495 32 0 10133703694198056054 6 0 12655387670867301210 36 0 1246525872821095171 51 1 812047498663608637 4 0 9797423115860097390 7 1 12105773148377740641 17 0 ...

output:

11875257514484243925
3443357416933857062
16160011677622853538
1582145987019406393
15019762274690743371
3128972641411454448
10632018957963074870
2420532366876270818
16130728863118353230
15834956073901517645
18404809296474853851
10982435108266120760
16463778300806795274
11990886156320593058
1145171640...

result: