2024.1.17做题纪要

lct 模板

没啥好说的,直接上

罗生门
#include <bits/stdc++.h>

const int SIZE = 3e5 + 9;

class link_cut_tree {
    #define lson (child[x][0])
    #define rson (child[x][1])

public:
    int child[SIZE][2], fat[SIZE];
    long long path[SIZE], value[SIZE];
    bool reverse[SIZE];

    void splay(int x) {
        int y, z;
        update(x);
        while (!is_root(x)) {
            y = fat[x];
            if (!is_root(y)) {
                if (direction(x) == direction(y))
                    rotate(y);
                else
                    rotate(x);
            }
            rotate(x);
        }
        pushup(x);
    }
    
    void pushup(int x) {
        path[x] = path[lson] ^ path[rson] ^ value[x];
    }

private:
    bool is_root(int x) {
        return (child[fat[x]][0] != x && child[fat[x]][1] != x);
    }

    void turn(int x) {
        std::swap(lson, rson);
        reverse[x] ^= 1;
    }

    bool direction(int x) {
        return (child[fat[x]][1] == x);
    }

    void pushdown(int x) {
        if (reverse[x]) {
            if (lson)
                turn(lson);
            if (rson)
                turn(rson);
            reverse[x] = 0;
        }
    }

    void rotate(int x) {
        int y = fat[x], z = fat[y], chk = direction(x);
        if (!is_root(y))
            child[z][child[z][1] == y] = x;
        if (child[x][!chk]) 
            fat[child[x][!chk]] = y;
        child[y][chk] = child[x][!chk];
        child[x][!chk] = y;
        fat[y] = x;
        fat[x] = z;
        pushup(y);
    }

    void update(int x) {
        if (!is_root(x))
            update(fat[x]);
        pushdown(x);
    }

    void access(int x) {
        for (int y = 0; x; y = x, x = fat[x]) {
            splay(x);
            child[x][1] = y;
            pushup(x);
        }
    }

    void make_root(int x) {
        access(x);
        splay(x);
        turn(x);
    }

    int find_root(int x) {
        access(x);
        splay(x);
        while (lson) {
            pushdown(x);
            x = lson;
        }
        splay(x);
        return x;
    }

public:
    void split(int x, int y) {
        make_root(x);
        access(y);
        splay(y);
    }

    void link(int x, int y) {
        make_root(x);
        if (find_root(y) != x)
            fat[x] = y;
    }

    void cut(int x, int y) {
        make_root(x);
        if (find_root(y) == x && fat[y] == x && !child[y][0]) {
            fat[y] = child[x][1] = 0;
            pushup(x);
        }
    }

    #undef lson
    #undef rson
}tree;

int N, M;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    std::cin >> N >> M;
    for (int i = 1; i <= N; ++ i)
        std::cin >> tree.value[i];
    
    while (M --) {
        int opt, x, y;
        std::cin >> opt >> x >> y;
        if (opt == 0) {
            tree.split(x, y);
            std::cout << tree.path[y] << '\n';
        }
        else if (opt == 1) {
            tree.link(x, y);
        }
        else if (opt == 2) {
            tree.cut(x, y);
        }
        else {
            tree.splay(x);
            tree.value[x] = y;
            tree.pushup(x);
        }
    }
    return 0;
}

[ARC112F] Die Siedler

妙妙题,感觉根本想不出来。

根号分治,还有同余最短路。

这个是真不会将,也太麻烦了。

我用什么把你留住
#include <bits/stdc++.h>

typedef long long ll;

ll N, M, P, d;
ll a[20], f[20], dis[2000000];

ll get_sum() {
    ll result = 0;
    for (int i = 1; i <= N; ++ i)   
        result += a[i] * f[i - 1];
    return result;
}

ll query(ll rest) {
    ll result = 0;
    for (int i = 1; i <= N; ++ i) {
        result += rest % (2 * i);
        rest = rest / (2 * i);
    }
    return result;
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    std::cin >> N >> M;
    f[0] = 1;
    for (int i = 1; i <= N; ++ i)
        f[i] = f[i - 1] * 2 * i;
    for (int i = 1; i <= N; ++ i) 
        std::cin >> a[i];
    P = get_sum();
    d = f[N] - 1;
    for (int i = 1; i <= M; ++ i) {
        for (int j = 1; j <= N; ++ j) 
            std::cin >> a[j];
        ll temp = get_sum();
        d = std::__gcd(d, temp);
    }
    if (P == 0) {
        std::cout << 0 << '\n';
        return 0;
    }
    if (d <= std::sqrt(f[N])) {
        std::queue<int> queue;

        memset(dis, -1, sizeof(dis));
        for (int i = 0; i < N; ++ i) {
            queue.emplace(f[i] % d);
            dis[f[i] % d] = 1;
        }
        while (queue.size()) {
            int now = queue.front();
            queue.pop();
            for (int i = 0; i < N; ++ i) {
                ll to = (now + f[i]) % d;
                if (dis[to] == -1) {
                    dis[to] = dis[now] + 1;
                    queue.emplace(to);
                }
            }
        }
        std::cout << std::min(query(P), dis[P % d]) << '\n';
    }
    else {
        ll answer = query(P);
        for (ll i = (P % d ? P % d : d); i < f[N]; i += d) 
            answer = std::min(answer, query(i));
        std::cout << answer << '\n';
    }
    return 0;
}

ALO

简单题,读明白题了就很板子。

我们将每个数从大到小排序。并从前向后遍历。

同时维护一个 \(set\),每次将当前的数插入后,查询在本位置左右两端最靠近本位置 \(i\) 的两个位置 \(l_1,l_2\)\(r_1,r_2\)\(l_1 \leq l_2,r_1 \leq r_2\))就行。

因为我们在插入当前数的时候,把比当前数大的数都在前面加了,所以合法区间就是 \(l_1 + 1\)\(i - 1\)\(i + 1\)\(r_2 - 1\)

清空
#include <bits/stdc++.h>

class Trie {
public:
    int root[51000], tot;
    int child[51000 * 35][2], max[51000 * 35];

    void insert(int rank, int number) {
        root[rank] = ++ tot;
        int now = root[rank];
        max[now] = rank;
        int last = root[rank - 1];

        for (int i = 30; i >= 0; -- i) {
            child[now][0] = child[last][0];
            child[now][1] = child[last][1];
            int ch = (number >> i) & 1;
            child[now][ch] = ++ tot;
            now = child[now][ch];
            last = child[last][ch];
            max[now] = rank;
        }
    }

    int ask(int l, int r, int number) {
        if (l > r)
            return number;
        int result = 0;
        int now = root[r];
        for (int i = 30; i >= 0; -- i) {
            int ch = (number >> i) & 1;
            int to = child[now][!ch];
            if (max[to] < l || !to) {
                now = child[now][ch];
                result += ((1 & ch) << i);
            }
            else {
                now = to;
                result += ((1 & (!ch)) << i);
            }
        }
        return result;
    }
}trie;

int N, answer;
std::pair<int, int> a[51000];
std::multiset<int> set;
bool visit[51000];

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    std::cin >> N;

    for (int i = 1; i <= N; ++ i) {
        std::cin >> a[i].first;
        trie.insert(i, a[i].first);
        a[i].first *= -1;
        a[i].second = i;
    }

    std::sort(a + 1, a + 1 + N);

    set.emplace(1);
    set.emplace(N);
    set.emplace(a[1].second);

    for (int i = 2; i <= N; ++ i) {
        a[i].first *= -1;
        set.emplace(a[i].second);
        std::multiset<int>::iterator iter = set.find(a[i].second);

        int left = *std::prev(iter);
        int right = *std::next(iter);

        if (left != 1)
            left = *std::prev(iter, 2) + 1;
        
        if (right != N)
            right = *std::next(iter, 2) - 1;
    
        int temp1 = trie.ask(left, a[i].second - 1, a[i].first);
        int temp2 = trie.ask(a[i].second + 1, right, a[i].first);
        answer = std::max({answer, temp1 ^ a[i].first, temp2 ^ a[i].first});
    }
    std::cout << answer << '\n';
    return 0;
}

[bzoj3956] Count

有点水平。

首先对于操作一是简单的不用管,重点去看操作二。

我们可以用上一个题:ALO 的方法处理出来每个数最靠近的左右两端的比它大的位置,然后插入可持久化线段树就行了。

counting stars
#include <bits/stdc++.h>

const int SIZE = 3e5 + 100;

class segment_tree {
    #define lid (lson[id])
    #define rid (rson[id])
public:
    int tot;
    std::pair<int, int> root[SIZE];
    int sum[SIZE * 70], lson[SIZE * 70], rson[SIZE * 70];

private:
    int make(int id) {
        ++ tot;
        sum[tot] = sum[id];
        lson[tot] = lson[id];
        rson[tot] = rson[id];
        return tot;
    }

    void pushup(int id) {
        sum[id] = sum[lid] + sum[rid];
    }

public:

    int update(int id, int l, int r, int pos) {
        id = make(id);

        if (l == r) {
            sum[id] ++;
            return id;
        }

        int mid = (l + r) >> 1;
        
        if (pos <= mid) 
            lid = update(lid, l, mid, pos);
        else
            rid = update(rid, mid + 1, r, pos);
        pushup(id);
        return id;
    }

    int query(int lRoot, int rRoot, int l, int r, int askL, int askR) {
        if (sum[rRoot] == sum[lRoot])
            return 0;
        if (askL <= l && r <= askR)  
            return sum[rRoot] - sum[lRoot];

        int mid = (l + r) >> 1, result = 0;

        if (askL <= mid)
            result += query(lson[lRoot], lson[rRoot], l, mid, askL, askR);
        if (mid + 1 <= askR)
            result += query(rson[lRoot], rson[rRoot], mid + 1, r, askL, askR);
        return result;
    }

    #undef lid
    #undef rid
}tree;

int N, M, type;
int num[310000], L[310000], R[310000];
std::pair<int, int> a[310000];
std::multiset<int> set;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);

    std::cin >> N >> M >> type;
    for (int i = 1; i <= N; ++ i) {
        std::cin >> num[i];
        a[i].first = -1 * num[i];
        a[i].second = i;
    }
    std::sort(a + 1, a + 1 + N);
    for (int j = 1, to; j <= N; j = to) {
        to = j;
        set.emplace(a[to].second);
        while (to + 1 <= N && a[to].first == a[to + 1].first) {
            set.emplace(a[to + 1].second);
            to ++;
        }

        for (int i = j; i <= to; ++ i) {
            std::multiset<int>::iterator iter = set.find(a[i].second);

            if (iter != set.begin())
                L[a[i].second] = *std::prev(iter);
            if (iter != std::prev(set.end())) 
                R[a[i].second] = *std::next(iter);
        }
        
        to ++;
    }

    for (int i = 1; i <= N; ++ i) {
        int last = std::max(tree.root[i - 1].first, tree.root[i - 1].second);

        tree.root[i] = std::make_pair(last, last);
        if (L[i] && L[i] != i - 1) 
            last = tree.root[i].first = tree.update(last, 1, N, L[i]);
        tree.root[i].second = last;
        if (R[i] && R[i] != i + 1 && num[R[i]] != num[i]) 
            tree.root[i].second = tree.update(last, 1, N, R[i]);
    }

    int answer = 0;
    for (int i = 1, l, r, u, v; i <= M; ++ i) {
        std::cin >> u >> v;
        if (type == 0) {
            l = u;
            r = v;
        }
        else {
            u = (u + answer - 1) % N + 1;
            v = (v + answer - 1) % N + 1;
            l = std::min(u, v);
            r = std::max(u, v);
        }
        int lRoot = std::max(tree.root[l - 1].first, tree.root[l - 1].second);
        int rRoot = std::max(tree.root[r].first, tree.root[r].second);
        answer = tree.query(lRoot, rRoot, 1, N, l, r) + (r - l);
        std::cout << answer << '\n';
    }

    return 0;
}
posted @ 2024-01-17 21:51  觉清风  阅读(28)  评论(2编辑  收藏  举报