zoukankan      html  css  js  c++  java
  • [分块] Codeforces 1619H Permutation and Queries

    题目大意

    给你一个 \(n(1\leq n\leq 10^5)\) 个数的排列 \(p\),你需要维护以下两种操作:

    • 1 x y :交换 \(p_x\)\(p_y\)
    • 2 i k :令 \(i:=p_i\)\(k\)次后输出\(i\)

    操作数量小于等于 \(10^5\)

    题解

    首先老套路对于排列 \(p\),从 \(i\)\(p_i\) 连边,可以形成若干个有向环。然后操作1交换 \(p_x\)\(p_y\) 实际上是改变环上两个指针的指向,可以导致一个环拆成两个环,或者两个环合并成一个环。所以数组模拟链表可以很容易建出这些有向环,并且很容易维护操作1。但是操作2比较难维护,因为链表无法支持随机访问。然后 \(O(n\log n)\) 好像没有什么好做法,于是就可以想 \(O(n\sqrt n)\) 的做法了。设 \(link[u]\) 表示从 \(u\) 点出发,往下跳 \(\sqrt n\) 次所跳到的点。那么相比于直接暴力跳 \(k\) 次,我们只需要跳 \(u:=link[u]\) 最多 \(\sqrt n\) 次,最后剩下的步数一定是小于 \(\sqrt n\) 的,可以暴力跳。于是单次查询操作的时间复杂度是 \(O(\sqrt n)\)。对于修改操作,因为交换两个指针可能导致 \(link[u]\) 发生变化,所以对于要修改指针的结点可以暴力回退 \(\sqrt n\) 的距离来更新 \(link[u]\)。于是本题的时间复杂度为 \(O(n\sqrt n)\)

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    template<typename elemType>
    inline void Read(elemType& T) {
        elemType X = 0, w = 0; char ch = 0;
        while (!isdigit(ch)) { w |= ch == '-';ch = getchar(); }
        while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
        T = (w ? -X : X);
    }
    
    int nxt[100010][2], link[100010];
    int n, m, q;
    
    void update_link(int u) {
        int v = u;
        for (int i = 1;i <= m;++i) v = nxt[v][0];
        for (int i = 1;i <= m;++i) { link[u] = v; u = nxt[u][1]; v = nxt[v][1]; }
    }
    
    void update(int u, int v) {
        int x = nxt[u][0], y = nxt[v][0];
        nxt[x][1] = v; nxt[y][1] = u;
        nxt[u][0] = y; nxt[v][0] = x;
        update_link(u);
        update_link(v);
    }
    
    int query(int u, int k) {
        int step = 0;
        while (step + m <= k) { u = link[u]; step += m; }
        while (step < k) { u = nxt[u][0]; ++step; }
        return u;
    }
    
    int main() {
        Read(n);Read(q);
        m = sqrt(n);
        for (int i = 1;i <= n;++i)
            Read(nxt[i][0]);
        for (int i = 1;i <= n;++i)
            nxt[nxt[i][0]][1] = i;
        for (int i = 1;i <= n;++i)
            if (!link[i]) update_link(i);
        while (q--) {
            int opt, x, y;
            Read(opt); Read(x); Read(y);
            if (opt == 1) update(x, y);
            else printf("%d\n", query(x, y));
        }
        return 0;
    }
    
  • 相关阅读:
    12.Django与ajax
    11.Django的分页器paginator
    10.中间键Middleware
    09.用户认证auth模块
    08.form组件
    07.会话跟踪技术cookie与session
    06.orm模型层
    05.Django模板层
    04.Django视图函数
    03.DjangoURL路由
  • 原文地址:https://www.cnblogs.com/AEMShana/p/15780780.html
Copyright © 2011-2022 走看看