【BZOJ2453】维护队列/【BZOJ2120】数颜色 分块
【BZOJ2453】维护队列
Description
Input
Output
Sample Input
1 2
Q 1 2
R 1 2
Q 1 2
Sample Output
1
HINT
对于100%的数据,有1 ≤ N ≤ 10000, 1 ≤ M ≤ 10000,小朋友A不会修改超过1000次,所有颜色均用1到10^6的整数表示。
题解:听说这题卡树套树(没写过)
我们还是考虑分块
一个经典的分块思路:我们用pre[i]表示i之前第一个与i颜色相同的弹珠,这样在询问时,在[l,r]中pre[i]小于l的i的个数就是答案。发现这个pre数组有一个很好的性质,即单调性,因此我们想到在教主的魔法那里用的办法,新建一个数组,块内按pre排序,这样就能二分查找出一个块内pre[i]<l的i的个数,然后就很容易了
现在我们考虑怎么修改,题目里说保证修改次数不多于1000,因此网上很多大犇都用的是暴力修改,但毕竟我们是读书人,怎能用暴力呢?
其实不用暴力修改也很(ju)容(ma)易(fan)
我们新开一个数组s[i][j]表示第i个块里,颜色为j个弹珠的个数。然后修改时我们要找到这个点:前面+后面,与原来的颜色相同的+与修改后颜色相同的,最近的点是哪个,(说白了就是维护pre数组),那我们就先在自己的块里找,然后在一个一个块扫,直接看s数组就可以知道块里有没有要找的数,然后在进入块里一个一个扫。时间复杂度:扫块sqrt(n),扫块内sqrt(n),所以加起来还是sqrt(n),比起那些O(n)来说简直有莫大的优越感
现在问题来了,你们想看压行的代码还是不压行的代码?反正我压了
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=11010;
int n,m,siz,ans,tot;
char str[5];
int p[maxn],q[maxn],ref[1000010],pre[maxn],s[110][maxn];
void rebuild(int x)
{
for(int i=x*siz;i<x*siz+siz;i++) q[i]=pre[i];
sort(q+x*siz,q+x*siz+siz);
}
int main()
{
scanf("%d%d",&n,&m);
siz=int(sqrt(1.0*n));
int i,j,k,a,b,l,r,mid,flag;
memset(ref,-1,sizeof(ref));
for(i=0;i<n;i++)
{
scanf("%d",&p[i]);
if(ref[p[i]]==-1) ref[p[i]]=++tot;
p[i]=ref[p[i]],s[i/siz][p[i]]++,pre[i]=-1,flag=0;
if(s[i/siz][p[i]]>1) for(k=i-1;k>=i/siz*siz&&!flag;k--) if(p[k]==p[i]) pre[i]=k,flag=1;
for(j=i/siz-1;j>=0&&!flag;j--) if(s[j][p[i]]) for(k=j*siz+siz-1;k>=j*siz&&!flag;k--) if(p[k]==p[i]) pre[i]=k,flag=1;
}
for(i=n;i<(n-1)/siz*siz+siz;i++) p[i]=pre[i]=1<<30;
for(i=0;i*siz<=n;i++) rebuild(i);
for(i=1;i<=m;i++)
{
scanf("%s%d%d",str,&a,&b);
if(str[0]=='Q')
{
a--,b--,ans=0;
if(a/siz==b/siz)
{
for(j=a;j<=b;j++) ans+=pre[j]<a;
printf("%d\n",ans);
continue;
}
for(j=a;j<a/siz*siz+siz;j++) ans+=pre[j]<a;
for(j=b/siz*siz;j<=b;j++) ans+=pre[j]<a;
for(j=a/siz*siz+siz;j<b/siz*siz;j+=siz)
{
l=j,r=j+siz;
while(l<r)
{
mid=l+r>>1;
if(q[mid]<a) l=mid+1;
else r=mid;
}
ans+=l-j;
}
printf("%d\n",ans);
}
else
{
flag=0,a--;
if(ref[b]==-1) ref[b]=++tot;
b=ref[b];
if(s[a/siz][p[a]]>1) for(k=a+1;k<a/siz*siz+siz&&!flag;k++) if(pre[k]==a) pre[k]=pre[a],flag=1;
for(j=a/siz+1;j*siz<n&&!flag;j++) if(s[j][p[a]]) for(k=j*siz;k<j*siz+siz&&!flag;k++) if(pre[k]==a) pre[k]=pre[a],flag=1,rebuild(j);
s[a/siz][p[a]]--,flag=0;
if(s[a/siz][b]) for(k=a-1;k>=a/siz*siz&&!flag;k--) if(p[k]==b) pre[a]=k,flag=1;
for(j=a/siz-1;j>=0&&!flag;j--) if(s[j][b]) for(k=j*siz+siz-1;k>=j*siz&&!flag;k--) if(p[k]==b) pre[a]=k,flag=1,rebuild(j);
if(!flag) pre[a]=-1;
flag=0;
if(s[a/siz][b]) for(k=a+1;k<a/siz*siz+siz&&!flag;k++) if(p[k]==b) pre[k]=a,flag=1;
for(j=a/siz+1;j*siz<n&&!flag;j++) if(s[j][b]) for(k=j*siz;k<j*siz+siz&&!flag;k++) if(p[k]==b) pre[k]=a,flag=1,rebuild(j);
s[a/siz][b]++,p[a]=b;
rebuild(a/siz);
}
}
return 0;
}
【BZOJ2453】维护队列/【BZOJ2120】数颜色 分块的更多相关文章
- BZOJ2453维护队列&&BZOJ2120数颜色
2016-05-28 11:20:22 共同的思路: 维护某种颜色上一次在哪里出现pre,可以知道当pre<询问的l时更新答案 块内按照pre排序 修改的时候重新O(n)扫一遍,如果和之前的不一 ...
- [BZOJ2120] 数颜色 && [bzoj2453] 维护队列(莫队 || 分块)
传送门 只有第一个,第二个权限题. 分块,然而wa,没看出来错在哪里,有时间再看. #include <cmath> #include <cstdio> #include &l ...
- bzoj2120 数颜色 分块
分块大法好 orz 处理出每个点的前驱和后继位置. 暴力修改,查询就在每个整块里查询pre<l的,暴力跑两边就好了 #include<cstdio> #include<cstr ...
- Luogu 1903 数颜色 | 分块
Luogu 1903 数颜色 | 分块 莫队不会啊-- 这道题直接分块也能卡过! 这道题的做法很有趣:对于每个位置i,记录它的颜色a[i]上一次出现的位置,记为pre[i]. 这样在查询一个区间[l, ...
- BZOJ2120 数颜色 【带修莫队】
BZOJ2120 数颜色 Description 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到 ...
- 【BZOJ-2453&2120】维护队列&数颜色 分块 + 带修莫队算法
2453: 维护队列 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 653 Solved: 283[Submit][Status][Discuss] ...
- Bzoj 2453: 维护队列 && Bzoj 2120: 数颜色 分块,bitset
2453: 维护队列 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 578 Solved: 247[Submit][Status][Discuss] ...
- BZOJ2453: 维护队列
2453: 维护队列 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 183 Solved: 89[Submit][Status] Descripti ...
- [bzoj2453]维护队列_带修改莫队
维护队列 bzoj-2453 题目大意:给定一个n个数序列,支持查询区间数的种类数,单点修改.不强制在线. 注释:$1\le n,m\le 10^5$. 想法: 带修改莫队裸题. 如果没有修改操作的话 ...
随机推荐
- WHAT EXACTLY IS WASM ?!
终于, 我入门了当初很仇视的技术.... 什么是WebAssembly? WebAssembly或WASM是一个编译器目标(由编译器生成的代码),具有二进制格式,允许我们在浏览器上执行C,C ++和R ...
- PHP并发IO编程之路
并发IO问题一直是服务器端编程中的技术难题,从最早的同步阻塞直接Fork进程,到Worker进程池/线程池,到现在的异步IO.协程.PHP程序员因为有强大的LAMP框架,对这类底层方面的知识知之甚少, ...
- Linux mysql5.5
1.假设已经有mysql-5.5.10.tar.gz以及cmake-2.8.4.tar.gz两个源文件 (1)先安装cmake(mysql5.5以后是通过cmake来编译的) [root@ rhel5 ...
- EMS快递单号生成算法
<?php function emsnum($ems, $num) { $fri = substr($ems, 2, 8); $head = substr($ems, 0, 2); $tail ...
- 关于ARM中的tst、cmp、bne、beq指令
一.关于cmp的详细用法 假设现在AX寄存器中的数是0002H,BX寄存器中的数是0003H. 执行的指令是:CMP AX, BX 执行这条指令时,先做用AX中的数减去BX中的数的减法运算. 列出二进 ...
- Ubuntu之命令壁纸
- Quartz是一个完全由java编写的开源作业调度框架
http://www.quartz-scheduler.org/ 找个时间研究一下
- python--条件判断和循环--3
原创博文,转载请标明出处--周学伟http://www.cnblogs.com/zxouxuewei/ 一.if语句 计算机之所以能做很多自动化的任务,因为它可以自己做条件判断. 比如,输入用户年龄, ...
- web.xml 中的listener、filter、servlet 加载顺序及其【配置详解】
在项目中总会遇到一些关于加载的优先级问题,近期也同样遇到过类似的,所以自己查找资料总结了下,下面有些是转载其他人的,毕竟人家写的不错,自己也就不重复造轮子了,只是略加点了自己的修饰. 首先可以肯定的是 ...
- python中模块,包,库
模块:就是.py文件,里面定义了一些函数和变量,需要的时候就可以导入这些模块. 包:在模块之上的概念,为了方便管理而将文件进行打包.包目录下第一个文件便是 __init__.py,然后是一些模块文件和 ...