51nod 1471 小S的兴趣 | 分块 链表
51nod 1471 小S的兴趣
题面
小S喜欢有趣的事。但是,每个人的兴趣都是独特的。小S热衷于自问自答。有一天,小S想出了一个问题。
有一个包含n个正整数的数组a和针对这个数组的几个问题。这些问题有两种类型:
在数组下标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('\n')
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;
}
51nod 1471 小S的兴趣 | 分块 链表的更多相关文章
- 51nod 1471 小S的兴趣 sqrt
小S喜欢有趣的事.但是,每个人的兴趣都是独特的.小S热衷于自问自答.有一天,小S想出了一个问题. 有一个包含n个正整数的数组a和针对这个数组的几个问题.这些问题有两种类型: 1. 在数组下标 ...
- 51nod1471 小S的兴趣
题目来源: CodeForces 基准时间限制:1.5 秒 空间限制:131072 KB 分值: 320 小S喜欢有趣的事.但是,每个人的兴趣都是独特的.小S热衷于自问自答.有一天,小S想出了一个问题 ...
- 【CF896E】Welcome home, Chtholly 暴力+分块+链表
[CF896E]Welcome home, Chtholly 题意:一个长度为n的序列ai,让你支持两种操作: 1.l r x:将[l,r]中ai>x的ai都减去x.2.l r x:询问[l,r ...
- bzoj 3781: 小B的询问 分块
3781: 小B的询问 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 196 Solved: 135[Submit][Status] Descrip ...
- 51nod 1589 移数博弈【桶排序+链表】
1589 移数博弈 基准时间限制:1 秒 空间限制:262144 KB 分值: 80 难度:5级算法题 小A和小B在玩一个游戏. 他们拥有一个数列. 小A在该数列中选择出最大的那个数,然后移出该数 ...
- 【BZOJ4548】小奇的糖果 set(链表)+树状数组
[BZOJ4548]小奇的糖果 Description 有 N 个彩色糖果在平面上.小奇想在平面上取一条水平的线段,并拾起它上方或下方的所有糖果.求出最多能够拾起多少糖果,使得获得的糖果并不包含所有的 ...
- 51nod 1631 小鲨鱼在51nod小学
基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题 鲨鱼巨巨2.0(以下简称小鲨鱼)以优异的成绩考入了51nod小学.并依靠算法方面的特长,在班里担任了许多职务. ...
- Codeforces 455D 分块+链表
题意: 给定一个长度为 N 的序列两种操作1 l r 将[l,r]的数向右循环移位 2 l r 询问[l,r]内有多少个数等于 k其中 N,Q≤105,ai≤N 强制在线 思路: 1. 每块用一个链表 ...
- AcWing 251. 小Z的袜子| 分块+莫队
传送门 题目描述 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿. 终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命. 具体来说,小Z把这N只袜子从 ...
随机推荐
- ThreadPoolExecutor 使用说明
它是一个ExecutorService,使用线程池中的线程执行提交的任务.通常我们使用Executors框架,定义使用. 线程池主要用来解决两类问题:通过缓存一定数量的可用线程,避免频繁的线程创建,销 ...
- arp与rarp
- 基于Linux-3.9.4内核增加简单的时间片轮转功能
简单的时间片轮转多道程序内核代码 原创作品转载请注明出处https://github.com/mengning/linuxkernel/ 作者:sa18225465 一.安装 Linux-3.9.4 ...
- 备份win10的驱动程序
目录 折腾历程 怎么备份驱动 备份的驱动如何使用 关于驱动程序的OS兼容性 驱动程序的其他安装方式 1.折腾历程 从闲鱼上收了一个INSIGNIA的二合一笔记本,w7100,因原装win10性能不行自 ...
- [Notice]博客地址转移 vitostack.com
个人博客地址转移至vitostack.com 这里可能不会经常更新. 欢迎访问新地址.
- Visual Studio AI配置环境
参考链接:http://www.cnblogs.com/ms-uap/p/9123033.html 背景: 1.能联网的电脑:Win7 64 SP1 2.鼠标.键盘.显示器好使 3.已安装VS2010 ...
- Scrum Meeting 11.03
成员 今日任务 明日计划 用时 徐越 休息 赵庶宏 编写功能说明书,servlet代码移植 servlet代码移植 3h 薄霖 阅读上一届相关代码,思考改进方法 学习安卓界面设计数据库管理 4 ...
- web02-welcomeyou
新建web项目web02-welcomeyou, 修改index.jsp为 <body> This is my JSP page. <br> <form action=& ...
- EF三种编程方式详细图文教程(C#+EF)之Code First
Code First Code First模式我们称之为“代码优先”模式,是从EF4.1开始新建加入的功能.使用Code First模式进行EF开发时开发人员只需要编写对应的数据类(其实就是领域模型的 ...
- Task 6.2冲刺会议五 /2015-5-18
今天继续深入的看了看服务器的内容,修改了昨天的代码,发现网络编程还是很好玩的,感觉他的代码比平常写的更有趣一点,另外登陆界面也稍微看了一点.明天准备把登陆界面完善一下.