51nod 1471 小S的兴趣 | 分块 链表

51nod 1471 小S的兴趣

题面

小S喜欢有趣的事。但是,每个人的兴趣都是独特的。小S热衷于自问自答。有一天,小S想出了一个问题。
有一个包含n个正整数的数组a和针对这个数组的几个问题。这些问题有两种类型:

  1.  在数组下标l到r的部分上,将一个单元格循环移动到右端。即以下面方式重新分配数组上的元素。
    

a[l], a[l+1], ..., a[r-1], a[r] → a[r], a[l], a[l+1], ..., a[r-1].
2. 在数组下标l到r的部分上,计算有多少元素的值与k相等。

小S很喜欢这个问题并且很快解决了它,你是否能够解决它呢?

Input

第一行包含整数 n (1 ≤ n ≤ 10*5) —数组元素的数量。第二行包含 n 个整数a[1], a[2], ..., a[n] (1 ≤ a[i] ≤ n)。

第三行包含唯一的整数 q (1 ≤ q ≤ 10*5) —问题的数量。接下来的q行包含了这些询问。

因为你需要在线回答这些问题,所以这些问题将会被编码。第一种类型的询问将会以以下形式给出: 1 Li Ri 。第二种类型的询问将会以以下形式给出: 2 Li Ri Ki 。所有输入的数字都是整数,它们满足以下条件:1 ≤ Li,Ri,Ki ≤ n.

为解码输入的问题,你需要按以下转换操作:
li = ((Li + lastans - 1) mod n) + 1;
ri = ((Ri + lastans - 1) mod n) + 1;
ki=((Ki + lastans - 1) mod n) + 1.
lastans 是到当前询问为止最后一个第二种类型的询问的答案 (初始, lastans = 0)。如果转换后, li 比 ri 大,你需要交换这两个数字。

Output

对于每一个第二种类型的问题以单独一行输出答案。

Input示例

7
6 6 2 7 4 2 5
7
1 3 6
2 2 4 2
2 2 4 7
2 2 2 5
1 2 6
1 1 4
2 1 7 3

Output示例

2
1
0
0

题解

这道题可以用分块做!(其实我就是想练习分块才来写的这道题……)

大约(sqrt n)(因为担心空间爆炸,我取的是400个一块)分成一块,每块内部是一个链表。对于每一块,记录某数在其中出现的次数。

当进行修改的时候,把右端点上的元素拿下来,插到左端点前面即可。但是单纯这样做,可能会导致有的块变大、有的块变小,不利于时间复杂度的稳定,于是把区间中间的每一块最右边的元素拿下来,插到下一个块的左端点前面,这样每次修改时块的大小不会改变。

注意可能出现修改区间的 l, r 相等的情况——对于我的代码,这里不特判的话链表操作就会GG……

#include <cstdio>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f
#define space putchar(' ')
#define enter putchar('
')
using namespace std;
typedef long long ll;
template <class T>
bool read(T &x){
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
        if(c == '-') op = 1;
        else if(c == EOF) return 0;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
        x = x * 10 + c - '0';
    if(op) x = -x;
    return 1;
}
template <class T>
void write(T x){
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}

const int M = 400, N = 1e5+400;
int n, q, a[N];
int st[N/M], ed[N/M], pre[N], nxt[N];
int blk[N], beg[N];
// 使用链表存储每一块内部信息
// blk是原来某一编号的元素的所在的位置
int cnt[N/M][N], ans; // 记录每一块内每个数有多少

void erase(int x){ //删除元素x
    pre[nxt[x]] = pre[x];
    nxt[pre[x]] = nxt[x];
    cnt[blk[x]][a[x]]--;
}
void insert(int x, int y){ //在x前面插入y(同一块)
    pre[y] = pre[x];
    nxt[y] = x;
    nxt[pre[x]] = y;
    pre[x] = y;
    blk[y] = blk[x];
    cnt[blk[y]][a[y]]++;
}
int find(int x){ //找到第x个元素
    int b = 1;
    while(b < blk[n] && beg[b + 1] <= x) b++;
    int ret = nxt[st[b]], pos = beg[b];
    while(pos < x) pos++, ret = nxt[ret];
    return ret;
}
void change(int l, int r){
    int left = find(l), right = find(r);
    int b1 = blk[left], b2 = blk[right];
    erase(right);
    insert(left, right);
    for(int b = b1; b < b2; b++){
        int x = pre[ed[b]];
        erase(x);
        insert(nxt[st[b + 1]], x);
    }
}
int query(int l, int r, int x){
    int left = find(l), right = find(r);
    int b1 = blk[left], b2 = blk[right];
    int ret = 0;
    if(b1 == b2){
        for(int i = left; i != nxt[right]; i = nxt[i])
            if(a[i] == x) ret++;
        return ret;
    }
    for(int pos = beg[b1 + 1] - 1, i = pre[ed[b1]]; pos >= l; pos--, i = pre[i])
        if(a[i] == x) ret++;
    for(int pos = beg[b2], i = nxt[st[b2]]; pos <= r; pos++, i = nxt[i])
        if(a[i] == x) ret++;
    for(int b = b1 + 1; b < b2; b++)
        ret += cnt[b][x];
    return ret;
}
int main(){
    read(n);
    for(int i = 1; i <= n; i++){
        read(a[i]);
        pre[i] = i - 1, nxt[i] = i + 1, blk[i] = (i - 1) / M + 1;
        if(i % M == 1)
            beg[blk[i]] = i, st[blk[i]] = n + blk[i], pre[i] = st[blk[i]], nxt[st[blk[i]]] = i;
        if(i % M == 0 || i == n)
            ed[blk[i]] = n + blk[i], nxt[i] = ed[blk[i]], pre[ed[blk[i]]] = i;
        cnt[blk[i]][a[i]]++;
    }
    beg[blk[n] + 1] = n + 1;
    read(q);
    while(q--){
        int op, l, r, x;
        read(op), read(l), read(r);
        l = (l + ans - 1) % n + 1;
        r = (r + ans - 1) % n + 1;
        if(l > r) swap(l, r);
        if(op == 1 && l != r)
            change(l, r);
        else if(op == 2){
            read(x);
            x = (x + ans - 1) % n + 1;
            write(ans = query(l, r, x)), enter;
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/RabbitHu/p/51nod1471.html