ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[分块] Codeforces 1619H Permutation and Queries

2022-01-09 13:33:59  阅读:166  来源: 互联网

标签:ch 1619H Queries sqrt 链表 link Permutation 操作 指针


题目大意

给你一个 \(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;
}

标签:ch,1619H,Queries,sqrt,链表,link,Permutation,操作,指针
来源: https://www.cnblogs.com/AEMShana/p/15780780.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有