分块神题。

看了一会儿题解,看懂了思路,然后写了两个小时,调了一个多小时,好多地方写错了。

我们考虑对序列和值域都分块。\(sum1[i][j]\) 表示前 \(i\) 个块,第 \(j\) 块值域有几个数,\(sum2[i][j]\) 表示前 \(i\) 个块,值为 \(j\) 有几个数,\(id[i][j]\) 表示第 \(i\) 块值为 \(j\) 的编号,\(mp[i][j]\) 表示第 \(i\) 块编号为 \(j\) 值为多少,这样空间正好开的下。

对于修改操作,我们考虑边角暴力。在整块中若只有 \(x\) 那么直接修改,若又有 \(y\) 的话就暴力重构。每次重构整块中不同的数的数目会 \(-1\),一个块最多被重构 \(\sqrt{n}\) 块,所以时间复杂度保证为 \(O(n\sqrt{n})\)

对于询问操作,我们利用 \(sum1\) 和 \(sum2\) 可以在 \(O(\sqrt{n})\) 得到。

时间复杂度 \(O(n\sqrt{n})\),空间复杂度 \(O(n\sqrt{n})\)

洛谷加了 \(fread,fwrite\) 才卡过去,空间差点 \(MLE\)。。。

\(Code\ Below:\)

#include <bits/stdc++.h>
using namespace std;
const int maxn=100000+10;
const int maxblo=317;
const int lim=100000;
int n,m,blo,a[maxn],pos[maxn],bl[maxn],L[maxn],R[maxn];
int v1[maxn],v2[maxn],sum1[maxblo][maxblo],sum2[maxblo][maxn],id[maxblo][maxn],mp[maxblo][maxblo]; namespace FastIO{
#define gc() (iS==iT?(iT=(iS=ibuff)+fread(ibuff,1,SIZ,stdin),(iS==iT?EOF:*iS++)):*iS++)
const int SIZ=1<<21|1;
char *iS,*iT,ibuff[SIZ],obuff[SIZ],*oS=obuff,*oT=oS+SIZ-1,fu[110],c;int fr;
inline void out(){
fwrite(obuff,1,oS-obuff,stdout);
oS=obuff;
}
template <class T>
inline void read(T &x){
x=0;T y=1;
for(c=gc();(c>'9'||c<'0')&&c!='-';c=gc());
c=='-'?y=-1:x=(c&15);
for(c=gc();c>='0'&&c<='9';c=gc()) x=x*10+(c&15);
x*=y;
}
template <class T>
inline void print(T x,char text='\n'){
if(x<0) *oS++='-',x*=-1;
if(x==0) *oS++='0';
while(x) fu[++fr]=x%10+'0',x/=10;
while(fr) *oS++=fu[fr--];
*oS++=text;out();
}
}
using namespace FastIO; inline void reset(int x){
for(int i=L[x];i<=R[x];i++) a[i]=mp[x][pos[i]];
} inline void change(int bel,int x,int y){
int last=id[bel][x];id[bel][y]=last;
mp[bel][last]=y;id[bel][x]=0;
} inline void build(int x){
for(int i=1;i<=blo;i++) id[x][mp[x][i]]=0;
int ind=0;
for(int i=L[x];i<=R[x];i++)
if(!id[x][a[i]]) id[x][a[i]]=++ind,mp[x][ind]=a[i];
for(int i=L[x];i<=R[x];i++) pos[i]=id[x][a[i]];
} inline void rebuild(int l,int x,int y){
for(int i=bl[l];i<=bl[n];i++){
sum1[i][bl[x]]+=sum1[i-1][bl[x]];
sum1[i][bl[y]]+=sum1[i-1][bl[y]];
sum2[i][x]+=sum2[i-1][x];
sum2[i][y]+=sum2[i-1][y];
}
} inline void modify(int l,int r,int x,int y){
if(sum2[bl[r]][x]==sum2[bl[l]-1][x]) return ;
for(int i=bl[n];i>=bl[l];i--){
sum1[i][bl[x]]-=sum1[i-1][bl[x]];
sum1[i][bl[y]]-=sum1[i-1][bl[y]];
sum2[i][x]-=sum2[i-1][x];
sum2[i][y]-=sum2[i-1][y];
}
if(bl[l]==bl[r]){
reset(bl[l]);
for(int i=l;i<=r;i++)
if(a[i]==x){
a[i]=y;
sum1[bl[l]][bl[x]]--;
sum1[bl[l]][bl[y]]++;
sum2[bl[l]][x]--;
sum2[bl[l]][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;
sum1[bl[l]][bl[x]]--;
sum1[bl[l]][bl[y]]++;
sum2[bl[l]][x]--;
sum2[bl[l]][y]++;
}
for(int i=L[bl[r]];i<=r;i++)
if(a[i]==x){
a[i]=y;
sum1[bl[r]][bl[x]]--;
sum1[bl[r]][bl[y]]++;
sum2[bl[r]][x]--;
sum2[bl[r]][y]++;
}
build(bl[l]);build(bl[r]);
for(int i=bl[l]+1;i<bl[r];i++){
if(!sum2[i][x]) continue;
if(sum2[i][y]){
reset(i);
for(int j=L[i];j<=R[i];j++)
if(a[j]==x){
a[j]=y;
sum1[i][bl[x]]--;
sum1[i][bl[y]]++;
sum2[i][x]--;
sum2[i][y]++;
}
build(i);
}
else {
sum1[i][bl[x]]-=sum2[i][x];
sum1[i][bl[y]]+=sum2[i][x];
sum2[i][y]+=sum2[i][x];
sum2[i][x]=0;
change(i,x,y);
}
}
rebuild(l,x,y);
} inline int query(int l,int r,int k){
if(bl[l]==bl[r]){
reset(bl[l]);
for(int i=l;i<=r;i++) v1[i]=a[i];
nth_element(v1+l,v1+l+k-1,v1+r+1);
int ans=v1[l+k-1];
for(int i=l;i<=r;i++) v1[i]=0;
return ans;
}
reset(bl[l]);reset(bl[r]);
for(int i=l;i<=R[bl[l]];i++) v1[bl[a[i]]]++,v2[a[i]]++;
for(int i=L[bl[r]];i<=r;i++) v1[bl[a[i]]]++,v2[a[i]]++;
for(int i=1;i<=bl[lim];i++){
if(k>v1[i]+sum1[bl[r]-1][i]-sum1[bl[l]][i]) k-=v1[i]+sum1[bl[r]-1][i]-sum1[bl[l]][i];
else {
for(int j=(i-1)*blo+1;j<=i*blo;j++){
if(k>v2[j]+sum2[bl[r]-1][j]-sum2[bl[l]][j]) k-=v2[j]+sum2[bl[r]-1][j]-sum2[bl[l]][j];
else {
for(int x=l;x<=R[bl[l]];x++) v1[bl[a[x]]]--,v2[a[x]]--;
for(int x=L[bl[r]];x<=r;x++) v1[bl[a[x]]]--,v2[a[x]]--;
return j;
}
}
}
}
} int main()
{
read(n),read(m);blo=sqrt(lim)+1;
for(int i=1;i<=n;i++) read(a[i]);
for(int i=1;i<=lim;i++){
bl[i]=(i-1)/blo+1;
if(bl[i]!=bl[i-1]) L[bl[i]]=i,R[bl[i-1]]=i-1;
}
R[bl[n]]=n;
for(int i=1;i<=bl[n];i++) build(i);
for(int x=1;x<=bl[n];x++){
for(int i=1;i<=bl[lim];i++) sum1[x][i]=sum1[x-1][i];
for(int i=1;i<=lim;i++) sum2[x][i]=sum2[x-1][i];
for(int i=L[x];i<=R[x];i++) sum1[x][bl[a[i]]]++,sum2[x][a[i]]++;
}
int op,l,r,x,y;
while(m--){
read(op),read(l),read(r),read(x);
if(op==1) read(y),modify(l,r,x,y);
else print(query(l,r,x));
}
return 0;
}

[Ynoi2018]未来日记(分块)的更多相关文章

  1. [Ynoi2018]未来日记

    "望月悲叹的最初分块" (妈呀这名字好中二啊(谁叫我要用日本轻小说中的东西命名真是作死)) 这里就直接挂csy的题解了,和我的不太一样,但是大概思路还是差不多的,我的做法是和“五彩 ...

  2. 「Ynoi2018」未来日记

    「Ynoi2018」未来日记 区间x->y,kth值... 不管了,先序列分块... 查询 第k值,假定知道每个数的权值,对值域分块. 对于整块,维护前\(i\)个块当中,值域在\(j\)块里以 ...

  3. 洛谷P4117 [Ynoi2018]五彩斑斓的世界 [分块,并查集]

    洛谷 Codeforces 又是一道卡常题-- 思路 YNOI当然要分块啦. 分块之后怎么办? 零散块暴力,整块怎么办? 显然不能暴力改/查询所有的.考虑把相同值的用并查集连在一起,这样修改时就只需要 ...

  4. [YNOI2018]五彩斑斓的世界&CF896E(分块+并查集)

    由于晚上比赛二连(Atcoder&codeforces),外加复习学考,所以暂时没时间写了. 贴个O(n√n)的分块代码,洛谷和cf上都过了,但垃圾bzoj卡不过去,不改了. #include ...

  5. ynoi2018

    题解: 全分块是啥操作啊.. 而且都好难.. 1.未来日记 这个比较简单 对每个块开个线段树维护权值 $n\sqrt{n}logn$ 这个会炸空间 并不能做... 但还是说一下做法 首先考虑分块 然后 ...

  6. PHP搭建大文件切割分块上传功能

    背景 在网站开发中,文件上传是很常见的一个功能.相信很多人都会遇到这种情况,想传一个文件上去,然后网页提示"该文件过大".因为一般情况下,我们都需要对上传的文件大小做限制,防止出现 ...

  7. POJ2104 K-th Number [分块做法]

    传送:主席树做法http://www.cnblogs.com/candy99/p/6160704.html 做那倒带修改的主席树时就发现分块可以做,然后就试了试 思想和教主的魔法差不多,只不过那个是求 ...

  8. HDU 4467 分块

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4467 题意:给定n个点m条边的无向图,点被染色(黑0/白1),边带边权.然后q个询问.询问分为两种: ...

  9. 2016 ACM/ICPC Asia Regional Dalian Online 1010 Weak Pair dfs序+分块

    Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submissio ...

随机推荐

  1. OPNET仿真软件资料合集

    1. OPEN中国代理商业 http://www.credit-top.com/page/Default.asp?pageID=105

  2. OneZero第三周第一次站立会议(2016.4.4)

    1. 时间: 13:30--13:45  共计15分钟. 2. 成员: X 夏一鸣 * 组长 (博客:http://www.cnblogs.com/xiaym896/), G 郭又铭 (博客:http ...

  3. docker使用自定义镜像zabbix服务

    一.关闭firewall,永久关闭,使用iptables防火墙 systemctl stop firewalld.service #停止firewall systemctl disable firew ...

  4. 再读c++primer plus 001

    1. OOP强调的是在运行阶段(而不是编译阶段)进行决策,运行阶段指的是程序正在运行时,编译阶段指的是编译器将程序组合起来时. 2.变量的值都存储在栈中,而new从被称为堆或自由存储区的内存区域分配内 ...

  5. kbmmw 5.04 发布

    增加了一大波功能,消灭了一大堆问题,也肯定引进了一大票BUG.We are happy to announce the release of our latest version of kbmMW. ...

  6. Ajax的爬取心得

    一.查找到js的网址 在我们做爬虫的时候,如何判断一个数据是Ajax(asynchronous JavaScript And Xml,异步的JavaScript和Xml), 首先是数据的加载,在请求网 ...

  7. swift-基础语法2

    一.整形 :有符号和无符号类型 有符号类型:Int ,Int8 ,Int32,Int64 无符号类型: UInt ,UInt8 UInt32,UInt64 注意点:如果你的开发环境是32位,那么Int ...

  8. 2019.01.22 bzoj3333: 排队计划(逆序对+线段树)

    传送门 题意简述:给出一个序列,支持把ppp~nnn中所有小于等于apa_pap​的'扯出来排序之后再放回去,要求动态维护全局逆序对. 思路:我们令fif_ifi​表示第iii个位置之后比它大的数的个 ...

  9. boost--signal

    1.signals2库 signals2库实现了线程安全的观察者模式,在signals2中观察者模式被称为信号/插槽(signals/slots),它是一种函数回调机制.一个信号可以关联一个或多个插槽 ...

  10. windows、linux下通过ftp上传文件小脚本

    一.windows @echo off #open ip 将要上传文件的IP地址echo open IP>ftp.up #用户名echo ninic>>ftp.up #密码echo ...