[Ynoi2018]未来日记
"望月悲叹的最初分块" (妈呀这名字好中二啊(谁叫我要用日本轻小说中的东西命名真是作死))
这里就直接挂csy的题解了,和我的不太一样,但是大概思路还是差不多的,我的做法是和“五彩斑斓的世界”有点类似的维护方法
先考虑如何求区间第k小值。对序列和权值都进行分块,设bi,j表示前j 块中权值在i 块内的数字个数,ci,j 表示前j 块中数字i 的出现次数。那么对于一个询问[l,r] ,首先将零碎部分的贡献加入到临时数组tb 和tc 中,然后枚举答案位于哪一块,确定位于哪一块之后再暴力枚举答案即可在O(√n) 的时间内求出区间第k小值。
接着考虑如何实现区间[l,r]内x 变成y 的功能。显然对于零碎的两块,可以直接暴力重构整块。对于中间的每个整块,如果某一块不含x ,那么无视这一块;否则如果这一块不含y ,那么只需要将x 映射成y ;否则这一块既有x 又有y ,这意味着x 与y 之间发生了合并,不妨直接暴力重构整块。因为有c 数组,我们可以在O(1) 的时间内知道某一块是否有某个数。
考虑什么情况下会发生重构,也就是一个块内发生了一次合并的时候。一开始长度为nn 的序列会提供O(n) 次合并的机会,而每次修改会对零碎的两块各提供一次机会,故总合并次数不超过O(n+m) ,因此当发生合并时直接重构并不会影响复杂度。
那么现在每块中的转换情况只可能是一条条互不相交的链,只需要记录每个初值转换后是什么,以及每个现值对应哪个初值即可。遇到查询的时候,我们需要知道零碎部分每个位置的值,不妨直接重构那两块,然后遍历一遍原数组a即可得到每个位置的值。
在修改的时候,还需要同步维护b 和c 数组,因为只涉及两个权值,因此暴力修改j 这一维也是可以承受的。
总时间复杂度O((n+m)√n) ,空间复杂度O(n√n)
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+,BLO=;
int n,m,a[N],p,vec[N],v2[BLO];
int bl[N],L[BLO],R[BLO];
int s1[BLO][BLO],s2[BLO][N],id[BLO][N],rid[BLO][BLO],pos[N];
int sta[],ttop=,lp=;
char pr[];
template <typename T> inline void read(T &x) {
x=;register char flag,c=getchar();while(c<''||c>'') flag=c,c=getchar();
while(c>=''&&c<='') x=x*+(c^),c=getchar(); if(flag=='-') x=-x;
}
template <typename T> inline void print(T x) {
ttop=; do { sta[++ttop]=(int)(x%),x/=; }while(x);
while(ttop) pr[lp++]=sta[ttop--]+''; pr[lp++]=;
}
inline void reset(int x) { for(register int i=L[x];i<=R[x];++i) a[i]=rid[x][pos[i]]; }
inline void change(int bel,int x,int y) {
int uid=id[bel][x];id[bel][y]=uid,rid[bel][uid]=y,id[bel][x]=;
}
inline void build(int x) {
for(register int i=;i<=p;++i) id[x][rid[x][i]]=;
for(register int i=L[x],idx=;i<=R[x];++i)
if(!id[x][a[i]])
id[x][a[i]]=++idx,rid[x][idx]=a[i];
for(register int i=L[x];i<=R[x];++i) pos[i]=id[x][a[i]];
}
inline void rebuild(int l,int x,int y) {
for(register int i=bl[l];i<=bl[n];++i) {
s2[i][x]+=s2[i-][x],s2[i][y]+=s2[i-][y];
s1[i][bl[x]]+=s1[i-][bl[x]],s1[i][bl[y]]+=s1[i-][bl[y]];
}
}
inline void modify(int l,int r,int x,int y) {
if(s2[bl[r]][x]-s2[bl[l]-][x]==) return ;
for(int i=bl[n];i>=bl[l];--i) {
s2[i][x]-=s2[i-][x],s2[i][y]-=s2[i-][y];
s1[i][bl[x]]-=s1[i-][bl[x]],s1[i][bl[y]]-=s1[i-][bl[y]];
}
if(bl[l]==bl[r]) {
reset(bl[l]);
for(int i=l;i<=r;++i)
if(a[i]==x) {
a[i]=y;
--s2[bl[l]][x],++s2[bl[l]][y];
--s1[bl[l]][bl[x]],++s1[bl[l]][bl[y]];
}
build(bl[l]),rebuild(l,x,y);return ;
}
reset(bl[l]),reset(bl[r]);
for(int i=l;i<=R[bl[l]];++i)
if(a[i]==x) {
a[i]=y;
--s2[bl[l]][x],++s2[bl[l]][y];
--s1[bl[l]][bl[x]],++s1[bl[l]][bl[y]];
}
for(int i=L[bl[r]];i<=r;++i)
if(a[i]==x) {
a[i]=y;
--s2[bl[r]][x],++s2[bl[r]][y];
--s1[bl[r]][bl[x]],++s1[bl[r]][bl[y]];
}
build(bl[l]),build(bl[r]);
for(int i=bl[l]+;i<bl[r];++i) {
if(!s2[i][x]) continue;
if(s2[i][y]) {
reset(i);
for(int j=L[i];j<=R[i];++j)
if(a[j]==x) {
a[j]=y;
--s2[i][x],++s2[i][y];
--s1[i][bl[x]],++s1[i][bl[y]];
}
build(i);
}
else {
s1[i][bl[y]]+=s2[i][x],s1[i][bl[x]]-=s2[i][x];
s2[i][y]+=s2[i][x],s2[i][x]=;
change(i,x,y);
}
}
rebuild(l,x,y);
}
inline int ask(int l,int r,int k) {
int ans=,sum=;
if(bl[l]==bl[r]) {
reset(bl[l]);for(int i=l;i<=r;++i) vec[i]=a[i];
nth_element(vec+l,vec+l+k-,vec+r+),ans=vec[l+k-];
for(int i=l;i<=r;++i) vec[i]=; return ans;
}
reset(bl[l]),reset(bl[r]);
for(int i=l;i<=R[bl[l]];++i) ++vec[a[i]],++v2[bl[a[i]]];
for(int i=L[bl[r]];i<=r;++i) ++vec[a[i]],++v2[bl[a[i]]];
for(int i=;i<=bl[N-];++i) {
if(sum+v2[i]+s1[bl[r]-][i]-s1[bl[l]][i]>=k) {
for(int j=(i-)*p+;j<=i*p;j++) {
if(vec[j]+s2[bl[r]-][j]-s2[bl[l]][j]+sum>=k) { ans=j;goto FLAG; }
else sum+=vec[j]+s2[bl[r]-][j]-s2[bl[l]][j];
}
}
else sum+=v2[i]+s1[bl[r]-][i]-s1[bl[l]][i];
}
FLAG:
for(int i=l;i<=R[bl[l]];++i) --vec[a[i]],--v2[bl[a[i]]];
for(int i=L[bl[r]];i<=r;++i) --vec[a[i]],--v2[bl[a[i]]];
return ans;
}
int main() {
read(n),read(m),p=sqrt(N)+;
for(int i=;i<N;++i) bl[i]=(i-)/p+;
for(int i=;i<=n;++i) read(a[i]);
for(int i=;i<=bl[n];++i)
L[i]=(i-)*p+,R[i]=i*p;R[bl[n]]=n;
for(int x=;x<=bl[n];++x) build(x);
for(int x=;x<=bl[n];++x) {
for(int i=;i<N;++i) s2[x][i]=s2[x-][i];
for(int i=;i<=bl[N-];++i) s1[x][i]=s1[x-][i];
for(int i=L[x];i<=R[x];++i) ++s1[x][bl[a[i]]],++s2[x][a[i]];
}
for(;m;--m) {
int opt,x,y;read(opt),read(x),read(y);
if(opt==) {int z,w;read(z),read(w),modify(x,y,z,w);}
else {int k;read(k),print(ask(x,y,k));}
}
pr[--lp]='\0'; puts(pr);
return ;
}
[Ynoi2018]未来日记的更多相关文章
- [Ynoi2018]未来日记(分块)
分块神题. 看了一会儿题解,看懂了思路,然后写了两个小时,调了一个多小时,好多地方写错了. 我们考虑对序列和值域都分块.\(sum1[i][j]\) 表示前 \(i\) 个块,第 \(j\) 块值域有 ...
- 「Ynoi2018」未来日记
「Ynoi2018」未来日记 区间x->y,kth值... 不管了,先序列分块... 查询 第k值,假定知道每个数的权值,对值域分块. 对于整块,维护前\(i\)个块当中,值域在\(j\)块里以 ...
- ynoi2018
题解: 全分块是啥操作啊.. 而且都好难.. 1.未来日记 这个比较简单 对每个块开个线段树维护权值 $n\sqrt{n}logn$ 这个会炸空间 并不能做... 但还是说一下做法 首先考虑分块 然后 ...
- [Ynoi2018]五彩斑斓的世界
题目描述 二阶堂真红给了你一个长为n的序列a,有m次操作 1.把区间[l,r]中大于x的数减去x 2.查询区间[l,r]中x的出现次数 题解 做YNOI真**爽... 我们发现这道题的操作非常诡异,把 ...
- [Ynoi2018]末日时在做什么?有没有空?可以来拯救吗?
这道题真的超级...毒瘤 + 卡常 + 耗 RP 啊... 传送门 noteskey 题解看 shadowice 大仙 的 code 如果发现自己 T 掉了,别心急,洗把脸再交一遍试试... //by ...
- 洛谷P4117 [Ynoi2018]五彩斑斓的世界 [分块,并查集]
洛谷 Codeforces 又是一道卡常题-- 思路 YNOI当然要分块啦. 分块之后怎么办? 零散块暴力,整块怎么办? 显然不能暴力改/查询所有的.考虑把相同值的用并查集连在一起,这样修改时就只需要 ...
- 【bzoj4810】【ynoi2018】由乃的玉米田
4810: [Ynoi2017]由乃的玉米田 Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 1090 Solved: 524[Submit][Sta ...
- 【洛谷5398】[Ynoi2018]GOSICK(二次离线莫队)
题目: 洛谷 5398 当我刚学莫队的时候,他们告诉我莫队能解决几乎所有区间问题: 现在,当我发现一个区间问题似乎难以用我所了解的莫队解决的时候,他们就把这题的正解叫做 XXX 莫队.--题记 (以上 ...
- 洛谷P5398 [Ynoi2018]GOSICK(二次离线莫队)
题面 传送门 题解 维包一生推 首先请确保您会二次离线莫队 那么我们现在的问题就是怎么转移了,对于\(i\)和前缀\([1,r]\)的贡献,我们拆成\(b_i\)和\(c_i\)两部分,其中\(b_i ...
随机推荐
- Django--Managers
Django--Managers Manager 概念: 1.Manager是Django中的数据模型,可以通过manager进行对数据库的查询操作.可以看其结构它本身是一个空的类,其主要的功能来自于 ...
- wc.exe
1 /* 2 * 没能实现的功能:wc.exe -s递归处理目录下符合条件的文件 3 * wc.exe -x 显示图形界面 4 * 5 * 6 * 实现的功能: wc.exe -c显示文件的字符数. ...
- C入门注意事项
C语言入门应该注意什么 进入IT行业,很多人一开始接触的都是C语言,C语言可以说是一门基础课程了,只要有了C语言的基础,那么以后不管是学什么语言都会比较容易上手.同时在学习其它语言时也可以 ...
- Ubuntu每次启动都显示System program problem detected
执行命令:sudo gedit /etc/default/apport 将enabled=1改为enabled=0保存退出
- 课下作业——MyCP
作业要求 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能,要求MyCP支持两个参数: java MyCP -tx XXX1.txt XXX2.bin 用来把文本文件(内容为 ...
- JS属性修改
document.getElementById('p1').style.visibility='visible' document.getElementById('p1').style.visibil ...
- oracle中创建数据库
一.在Oracle中创建数据库之前先改一下虚拟机的IP地址,以便访问 2. 3. 3.1 3.2 3.3 3.4 创建完成:输入sqlplus sys/123456 as sysdba测试
- xss处理
今天学习了xss,主要记载如下: https://blog.csdn.net/sdauzyh/article/details/74942737
- Python成长之路【第二篇】Python基础之数据类型
阅读目录 简介 1 什么是数据? x=10,10是我们要存储的数据 2 为何数据要分不同的类型 数据是用来表示状态的,不同的状态就应该用不同的类型的数据去表示 3 数据类型 数字(整形,长整形,浮点型 ...
- LimeSDR 上手指南
原文链接:https://mp.weixin.qq.com/s/so4XzPaYtzAvgbjarm_9fg 有问题可以在公众号或者这里留言