[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 ...
随机推荐
- onmouseover与onmouseenter区别
1.onmouseover.onmouseout:鼠标经过时自身触发事件,经过其子元素时也触发该事件:(父亲有的东西,儿子也有) ,支持冒泡 2.onmouseenter.onmouseleave:鼠 ...
- JDBCUtils——DBCP
需要导入的包: mysql-connector-java-5.1.37-bin.jar commons-dbcp-1.4.jar commons-pool-1.6.jar 需要添加/配置的配置文件: ...
- Cronolog日志分割、定时清理
阿里云发送短信提示服务器磁盘占用到80%警报短信 经过排查发现tomcat日志文件达到10个多G,手动删除过久的日志文件后恢复到50% 但是catalina.out文件还有6个G 解决方法 一.安装C ...
- 关于web项目中静态资源加载不了的一些解决思路
问题的产生: <!--springMVC前端控制器加载--> <servlet> <servlet-name>springmvc</servlet-name& ...
- Python 3 基本操作列举
1.字符串 2,列表 3.random库 计算机产生的随机数都是有一个种子开始的伪随机序列,相同的随机种子产生相同的伪随机数序列. >>> random.seed(10) >& ...
- c++中,如果访问数组越界,程序可能会意外终止(像死循环)
#include<iostream> using namespace std; ];// int main(){ vis[]=;//访问越界 ; } 程序错误表现:
- 基于IntelliJ IDEA开发工具搭建SSM框架并实现页面登录功能详细讲解二
接: 接下来配置类 UserController package com.chatRotbot.controller; import com.chatRotbot.model.User; import ...
- ios中iframe页面出现白屏问题
最近用ionic3开发的一个项目在ios中出现了白屏的问题 banner轮播图跳转网页 使用了iframe 但是却时不时的出现白屏现象 在android中一切正常 网上查资料发现 是因为ios不允许访 ...
- soapui 测试 带hear 验证的写法
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web=& ...
- Swing学习2——图标添加Icon接口使用
废话没有,看代码. 主要就是通过实现Icon接口在标签添加一个圆形图标,并在框架中显示. package com.sword.swing_test; import javax.swing.*; imp ...