P4119 [Ynoi2018] 未来日记

它来了!

分析一下第一个操作,不是写过嘛,并查集

分析一下第二个操作,二分套二分答案

拿下了这题

仔细分析,貌似时间复杂度是错的O(sqrt(n)*nlognlogv)

我们考虑块套块 时间复杂度O(n*sqrt(n))

对1e5的值域进行分块

求k值我们可以先找是第几个块,再找到是块内第几个数

如何做?

散块

我们可以做一个桶来临时存数量

整块

我们可以做一个前缀和,O(1)询问范围内的数量与k的关系,小于k我们就累加,否则我们就找到了那个块,找到第几个数也是一样的原理

因此我们维护bc[i][j] i个块内 j个值域块内的数量,c[i][j] i个块内j个数值的数量,那么散块也需要临时维护t1[i]第i个值域块的数量,t2[i]第i个数值的数量,提前预处理

如果只有一个散块可以直接找nth_element

inline int kth(int l,int r,int k){int p=pos[l];int q=pos[r];ll res=0;ll sum=0;if(p==q){pushdown(p);for(int i=l;i<=r;i++){t2[i]=a[i];}nth_element(t2+l,t2+l+k-1,t2+r+1);res=t2[l+k-1];//0->kfor(int i=l;i<=r;i++){t2[i]=0;//清空}}else{//散块计数pushdown(p);for(int i=l;i<=R[p];i++){t1[PP[a[i]]]++;t2[a[i]]++;}pushdown(q);for(int i=L[q];i<=r;i++){t1[PP[a[i]]]++;t2[a[i]]++;}//整块处理for(int i=1;i<=tt;i++){//枚举值域块if(sum+t1[i]+bc[q-1][i]-bc[p][i]>=k){//[p+1,q-1]for(int j=LL[i];j<=RR[i];j++){//枚举块内值域if(sum+t2[j]+c[q-1][j]-c[p][j]>=k){//找到位置//查询结束前清空for(int o=l;o<=R[p];o++){//[l,R[p]]t1[PP[a[o]]]--;t2[a[o]]--;}for(int o=L[q];o<=r;o++){//[R[q],r]t1[PP[a[o]]]--;t2[a[o]]--;}//返回答案return j;//kth}else{sum+=(t2[j]+c[q-1][j]-c[p][j]);}}}else{sum+=(t1[i]+bc[q-1][i]-bc[p][i]);//累加}}}return res;
}

结合操作一

我们维护val[i][j] 记录在第i块内的第j个位置的值,index[i][j]记录在第i个块内的a[j]在什么位置

loc[i]记录index[i][a[i]]

预处理

inline void build(int id){//建立关系int cur=0;//根标号for(int i=1;i<=blo;i++){//清空关系index[id][val[id][i]]=0;}for(int i=L[id];i<=R[id];i++){if(!index[id][a[i]]){cur++;index[id][a[i]]=cur;val[id][cur]=a[i];}loc[i]=index[id][a[i]];}
}

这样我们可以通过3个数组推出a[i]的真实值

inline void pushdown(int id){//还原数组for(int i=L[id];i<=R[id];i++){a[i]=val[id][loc[i]];//}
}

合并操作

inline void merge(int id,int x,int y){//合并index[id][y]=index[id][x];val[id][index[id][x]]=y;index[id][x]=0;
}

 修改我们考虑差分,再单块处理后,前缀和,时间复杂度不变

散块

直接modify

整块

如果没有x,直接跳过

如果没有x,有y  转移贡献

如果有x,有y  +合并

inline void modify(int l,int r,int x,int y){//散块for(int i=l;i<=r;i++){if(a[i]==x){bc[pos[i]][PP[x]]--;bc[pos[i]][PP[y]]++;c[pos[i]][x]--;c[pos[i]][y]++;a[i]=y;}}
}
inline void update(int l,int r,int x,int y){//处理每个块的数据可以差分处理if((x==y) || c[pos[r]][x]-c[pos[l]-1][x]==0 ){//x==y 或者是 区间内没有xreturn;}//差分单独处理这块的答案for(int i=t;i>=pos[l];i--){bc[i][PP[x]]-=bc[i-1][PP[x]];bc[i][PP[y]]-=bc[i-1][PP[y]];c[i][x]-=c[i-1][x];c[i][y]-=c[i-1][y];}int p=pos[l];int q=pos[r];if(p==q){pushdown(p);modify(l,r,x,y);//散块build(p);for(int i=p;i<=t;i++){bc[i][PP[x]]+=bc[i-1][PP[x]];bc[i][PP[y]]+=bc[i-1][PP[y]];c[i][x]+=c[i-1][x];c[i][y]+=c[i-1][y]; }}else{pushdown(p);modify(l,R[p],x,y);//散块build(p);pushdown(q);modify(L[q],r,x,y);//散块build(q);for(int i=p+1;i<=q-1;i++){if(!c[i][x]){//不存在x continue;}else if(c[i][y]){pushdown(i);modify(L[i],R[i],x,y);build(i);	}else{bc[i][PP[y]]+=c[i][x];bc[i][PP[x]]-=c[i][x];c[i][y]+=c[i][x];c[i][x]=0;merge(i,x,y);}}for(int i=p;i<=t;i++){bc[i][PP[x]]+=bc[i-1][PP[x]];bc[i][PP[y]]+=bc[i-1][PP[y]];c[i][x]+=c[i-1][x];c[i][y]+=c[i-1][y]; }}
}

完整代码

#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#define INF (1ll<<60)
using namespace std;
typedef long long ll;
namespace Lan {inline string sread() {string s=" ";char e=getchar();while(e==' '||e=='\n')e=getchar();while(e!=' '&&e!='\n')s+=e,e=getchar();return s;}inline void swrite(string s){for(char e:s)putchar(e);printf("\n");}inline ll read() {ll x=0,y=1;char c=getchar();while(!isdigit(c)){if(c=='-')y=-1;c=getchar();}while(isdigit(c)){x=(x<<3)+(x<<1)+(c^48);c=getchar();}return x*=y;}inline void write(ll x) {if(x<0){x=-x,putchar('-');}ll sta[35],top=0;do sta[top++]=x%10,x/=10;while(x);while(top)putchar(sta[--top]+'0');}
}using namespace Lan;
const int N=1e5+9;
const int M=1e5+2;
const int B=5e2+9;
int a[N],bc[B][N],c[B][N];//块内的值域块中的数的数量,以及该数值的数
int L[B],R[B],pos[N];
int LL[B],RR[B],PP[N];
int index[B][N],val[B][N],loc[N];
int t1[B],t2[N];//散块查kth
int blo,t,tt;
inline void merge(int id,int x,int y){//合并index[id][y]=index[id][x];val[id][index[id][x]]=y;index[id][x]=0;
}
inline void pushdown(int id){//还原数组for(int i=L[id];i<=R[id];i++){a[i]=val[id][loc[i]];//}
}
inline void build(int id){//建立关系int cur=0;//根标号for(int i=1;i<=blo;i++){//清空关系index[id][val[id][i]]=0;}for(int i=L[id];i<=R[id];i++){if(!index[id][a[i]]){cur++;index[id][a[i]]=cur;val[id][cur]=a[i];}loc[i]=index[id][a[i]];}
}
inline void modify(int l,int r,int x,int y){//散块for(int i=l;i<=r;i++){if(a[i]==x){bc[pos[i]][PP[x]]--;bc[pos[i]][PP[y]]++;c[pos[i]][x]--;c[pos[i]][y]++;a[i]=y;}}
}
inline void update(int l,int r,int x,int y){//处理每个块的数据可以差分处理if((x==y) || c[pos[r]][x]-c[pos[l]-1][x]==0 ){//x==y 或者是 区间内没有xreturn;}//差分单独处理这块的答案for(int i=t;i>=pos[l];i--){bc[i][PP[x]]-=bc[i-1][PP[x]];bc[i][PP[y]]-=bc[i-1][PP[y]];c[i][x]-=c[i-1][x];c[i][y]-=c[i-1][y];}int p=pos[l];int q=pos[r];if(p==q){pushdown(p);modify(l,r,x,y);//散块build(p);for(int i=p;i<=t;i++){bc[i][PP[x]]+=bc[i-1][PP[x]];bc[i][PP[y]]+=bc[i-1][PP[y]];c[i][x]+=c[i-1][x];c[i][y]+=c[i-1][y]; }}else{pushdown(p);modify(l,R[p],x,y);//散块build(p);pushdown(q);modify(L[q],r,x,y);//散块build(q);for(int i=p+1;i<=q-1;i++){if(!c[i][x]){//不存在x continue;}else if(c[i][y]){pushdown(i);modify(L[i],R[i],x,y);build(i);	}else{bc[i][PP[y]]+=c[i][x];bc[i][PP[x]]-=c[i][x];c[i][y]+=c[i][x];c[i][x]=0;merge(i,x,y);}}for(int i=p;i<=t;i++){bc[i][PP[x]]+=bc[i-1][PP[x]];bc[i][PP[y]]+=bc[i-1][PP[y]];c[i][x]+=c[i-1][x];c[i][y]+=c[i-1][y]; }}
}
inline int kth(int l,int r,int k){int p=pos[l];int q=pos[r];ll res=0;ll sum=0;if(p==q){pushdown(p);for(int i=l;i<=r;i++){t2[i]=a[i];}nth_element(t2+l,t2+l+k-1,t2+r+1);res=t2[l+k-1];//0->kfor(int i=l;i<=r;i++){t2[i]=0;//清空}}else{//散块计数pushdown(p);for(int i=l;i<=R[p];i++){t1[PP[a[i]]]++;t2[a[i]]++;}pushdown(q);for(int i=L[q];i<=r;i++){t1[PP[a[i]]]++;t2[a[i]]++;}//整块处理for(int i=1;i<=tt;i++){//枚举值域块if(sum+t1[i]+bc[q-1][i]-bc[p][i]>=k){//[p+1,q-1]for(int j=LL[i];j<=RR[i];j++){//枚举块内值域if(sum+t2[j]+c[q-1][j]-c[p][j]>=k){//找到位置//查询结束前清空for(int o=l;o<=R[p];o++){//[l,R[p]]t1[PP[a[o]]]--;t2[a[o]]--;}for(int o=L[q];o<=r;o++){//[R[q],r]t1[PP[a[o]]]--;t2[a[o]]--;}//返回答案return j;//kth}else{sum+=(t2[j]+c[q-1][j]-c[p][j]);}}}else{sum+=(t1[i]+bc[q-1][i]-bc[p][i]);//累加}}}return res;
}
int main(){// ios::sync_with_stdio(false);// cin.tie(0),cout.tie(0);int n,m;n=read(),m=read();for(int i=1;i<=n;i++){a[i]=read();}//分块blo=sqrt(n);t=sqrt(n);for(int i=1;i<=t;i++){L[i]=(i-1)*t+1;R[i]=i*t;}if(R[t]<n){t++;L[t]=R[t-1]+1;R[t]=n;}for(int i=1;i<=t;i++){for(int j=L[i];j<=R[i];j++){pos[j]=i;}}//值域分块tt=sqrt(M);for(int i=1;i<=tt;i++){LL[i]=(i-1)*tt+1;RR[i]=i*tt;}if(RR[tt]<M){tt++;LL[tt]=RR[tt-1]+1;RR[tt]=M;}for(int i=1;i<=tt;i++){for(int j=LL[i];j<=RR[i];j++){PP[j]=i;}}//预处理//值域分块for(int i=1;i<=t;i++){for(int j=1;j<=t+100;j++){bc[i][j]=bc[i-1][j];//块继承}for(int j=1;j<M;j++){c[i][j]=c[i-1][j];//数量继承}for(int j=L[i];j<=R[i];j++){bc[i][PP[a[j]]]++;//继续记录c[i][a[j]]++;}}//并查集for(int i=1;i<=t;i++){build(i);}for(int i=1;i<=m;i++){int op;op=read();int l,r;l=read(),r=read();if(op==1){int x,y;x=read(),y=read();update(l,r,x,y);}else{int k;k=read();cout<<kth(l,r,k)<<'\n';}}return 0;
}

学会了值域分块求k值,学完第二分块并查集,感觉第一分块的操作一并查集那块挺好写的

差分修改还是很妙的

下一个大分块 maybe 天降之物?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/812622.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

word并排比较

Word并排比较是一种在Microsoft Word文档中同时显示两个文本内容并进行比较的功能。这种比较通常用于查看文档的不同版本之间的差异&#xff0c;或者比较两个不同来源的文本内容。 在Word中进行并排比较通常可以通过以下步骤实现&#xff1a; 通过这种方式&#xff0c;Word的并…

灯光1-灯光与阴影的关系

灯光与阴影之间存在密切的关系。在计算机图形学和视觉效果中&#xff0c;灯光是用来模拟现实世界中的光照情况的一种技术。通过设置不同的灯光属性和位置&#xff0c;可以产生各种不同的光照效果&#xff0c;其中之一就是阴影。 当一个物体被照亮时&#xff0c;光线会被物体表…

2024阿里云学生服务器申请图文全流程,学生机免费续费攻略

2024年阿里云学生服务器免费申请&#xff0c;完成学生认证可以领取1个月免费学生机&#xff0c;完成任务可以再免费学费6个月时长&#xff0c;还可以领取高校计划学生300元无门槛优惠代金券&#xff0c;阿里云服务器网aliyunfuwuqi.com整理2024年最新阿里云大学生服务器申请入口…

国内代理IP对网络安全的影响及其应对策略

国内代理IP对网络安全的影响主要体现在以下几个方面&#xff1a; 1. 隐私保护&#xff1a; - 使用国内代理IP可以隐藏用户的真实IP地址&#xff0c;增加网络匿名性。这有助于防止第三方追踪用户的在线活动&#xff0c;减少个人信息泄露的风险&#xff0c;特别是对于敏感操作或访…

8路HDMI+8路AV高清视频流媒体编码器JR-3218HD

产品简介&#xff1a; JR-3218HD高清音视频编码产品支持8路高清HDMI音视频采集功能&#xff0c;8路AV视频采集功能&#xff0c;8路3.5MM独独立音频接口采集功能。编码输出双码流H.264格式&#xff0c;音频MP3/AAC格式。编码码率可调&#xff0c;画面质量可控制。支持HTTP/RTSP…

企业在申请火力发电资质中的人才队伍建设瓶颈

企业在申请火力发电资质的过程中&#xff0c;人才队伍建设常常面临一系列瓶颈问题。这些问题不仅影响企业的资质申请进度&#xff0c;还可能制约企业的长远发展。以下是一些主要的人才队伍建设瓶颈&#xff1a; 首先&#xff0c;专业技术人才短缺是一个突出问题。火力发电行业…

SpringBoot中的yaml 与properties文件书写格式

本文参考https://c.biancheng.net/spring_boot/example.html SpringBoot starter Spring Boot 将日常企业应用研发中的各种场景都抽取出来&#xff0c;做成一个个的 starter&#xff08;启动器&#xff09;&#xff0c;starter 中整合了该场景下各种可能用到的依赖&#xff…

引人共鸣的情感视频素材在哪找?今天看这五个网站

朋友们好啊&#xff0c;最近是不是不少人都在发愁啊&#xff0c;优秀创作者做视频用的视频素材哪来的啊&#xff1f;今天我为朋友们准备了几个优秀的视频素材网站&#xff0c;让你们做视频不再缺少素材&#xff0c;然后还有几个辅助创作的工具&#xff0c;都是你们需要的&#…

算法与数据结构 顺序栈(C++)

随机产生10个100以内的整数建立一个顺序栈&#xff0c;从栈顶到栈底依次显示栈内元素&#xff1b;从键盘输入出栈元素个数 n (1< n <10)&#xff0c;将 n 个元素依次出栈并显示出栈元素&#xff0c;再显示此时栈顶元素。 #include <iostream> #include <cstd…

电源——BUCK详解

目录 BUCK电路工作原理3种工作模式 BUCK电路实操PCB如何降低EMI和EMC及注意事项 BUCK电路工作原理 如图&#xff0c;给一个一定频率的PWM波控制Q1&#xff0c;使得输入电压不停的导通断开&#xff0c;达到降压的目的。 输入电压 * 占空比 输出电压 非隔离 输入与输出的极性相同…

mysql 大表凌晨定时删除数据

有几张表数据量非常大&#xff0c;一次维护量有点大&#xff08;一个月有500多万条数据&#xff0c;并且还在往上涨&#xff09;&#xff0c; 于是想了个定时删除数据&#xff0c;每天凌晨执行&#xff0c;这样每天删除数据量就小&#xff0c; 循环删除&#xff0c;每次删除5…

CSS导读 (复合选择器 上)

&#xff08;大家好&#xff0c;今天我们将继续来学习CSS的相关知识&#xff0c;大家可以在评论区进行互动答疑哦~加油&#xff01;&#x1f495;&#xff09; 目录 二、CSS的复合选择器 2.1 什么是复合选择器 2.2 后代选择器(重要) 2.3 子选择器(重要) Questions 小提…

贝乐虎儿歌v6.8.0解锁高级版亲子学习儿歌

软件介绍 贝乐虎儿歌免费版app&#xff0c;出自乐擎网络的创意工坊&#xff0c;专为孩子们雕琢了一系列富含创意的动画儿歌内容。这款app通过贝乐虎兄弟的可爱形象&#xff0c;让孩子们在愉快的观看中接触到各种儿歌和故事。不仅如此&#xff0c;app还巧妙地将古诗、英语等学习…

Bytebase 2.15.0 - GitOps 整体升级

&#x1f514; GitOps 整体升级 新版 GitOps 和之前版本不兼容&#xff0c;如果需要升级协助&#xff0c;请联系我们。 使用访问令牌进行身份验证。支持项目中配置多个 VCS 连接器。支持在 VCS 连接器中指定数据库分组为目标&#xff08;默认情况下应用于项目中的所有数据库&…

Python | Leetcode Python题解之第25题K个一组翻转链表

题目&#xff1a; 题解&#xff1a; class Solution:# 翻转一个子链表&#xff0c;并且返回新的头与尾def reverse(self, head: ListNode, tail: ListNode):prev tail.nextp headwhile prev ! tail:nex p.nextp.next prevprev pp nexreturn tail, headdef reverseKGroup…

【教学类-52-03】20240412动物数独(4宫格)难度1-9 打印版

作品展示&#xff1a;合并打印&#xff08;难度10%-90%&#xff0c;一共9份&#xff09; 背景需求 前期两个代码完成了4宫格基本样式的制作 【教学类-52-01】20240411动物数独&#xff08;4宫格&#xff09;宫格图https://mp.csdn.net/mp_blog/creation/editor/137679361【教学…

C++11中的lambda、包装器(function、bind)

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C &#x1f525;座右铭&#xff1a;“不要等到什么都没有了&#xff0c;才下…

CSS-浮动文字环绕布局、隐藏属性display、overflow、三角形制作、鼠标样式

文字环绕布局 CSS文字环绕布局是指在网页中让文字环绕在图片或其他元素周围的布局方式。这通常通过CSS中的float属性来实现。你可以将图片设置为float: left;或float: right;&#xff0c;然后在文本元素中使用clear属性来清除浮动&#xff0c;以确保文字不会覆盖图片。另外&am…

实用工具系列-git常用命令

作者持续关注 WPS二次开发专题系列&#xff0c;持续为大家带来更多有价值的WPS开发技术细节&#xff0c;如果能够帮助到您&#xff0c;请帮忙来个一键三连&#xff0c;更多问题请联系我&#xff08;WPS二次开发QQ群:250325397&#xff09;&#xff0c;摸鱼吹牛嗨起来&#xff0…

kylin v10 php源码安装后配置nginx

银河麒麟V10 源码编译安装php7.4 下载地址 https://www.php.net/distributions/php-7.4.33.tar.xz 安装依赖包&#xff0c;准备编译 dnf install libxml2-devel sqlite-devel bzip2-devel libcurl-devel libjpeg-turbo-devel freetype-devel openldap-devel libtool-devel p…