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的并…

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

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

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;优秀创作者做视频用的视频素材哪来的啊&#xff1f;今天我为朋友们准备了几个优秀的视频素材网站&#xff0c;让你们做视频不再缺少素材&#xff0c;然后还有几个辅助创作的工具&#xff0c;都是你们需要的&#…

电源——BUCK详解

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

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【教学…

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

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

引领未来:杭州2024快递物流展共绘创新浪潮,塑造智慧物流新蓝图

杭州&#xff0c;作为中国的电商之都&#xff0c;近年来在快递物流行业背景与应用方面取得了显著的发展。随着电子商务的迅猛增长&#xff0c;杭州的快递物流行业迅速崛起&#xff0c;成为支撑电商产业发展的重要力量。 2024长三角&#xff08;杭州&#xff09;快递物流供应链与…

FFmpeg: 简易ijkplayer播放器实现--05ijkplayer–连接UI界面和ffplay.c

文章目录 ijkplayer时序图消息循环--回调函数实现播放器播放时状态转换播放停止 ijkmediaPlay成员变量成员函数 ijkplayer时序图 stream_open: frame_queue_init packet_queue_init init_clock 创建read_thread线程 创建video_refresh_thread线程 消息循环–回调函数实现 ui …

从吉客云到MySQL通过接口配置打通数据

从吉客云到MySQL通过接口配置打通数据 数据源系统:吉客云 吉客云是基于“网店管家”十五年电商ERP行业和技术积累基础上顺应产业发展需求&#xff0c;重新定位、全新设计推出的换代产品&#xff0c;从业务数字化和组织数字化两个方向出发&#xff0c;以构建流程的闭环为依归&am…

大数据入门之如何利用Phoenix访问Hbase

在大数据的世界里&#xff0c;HBase和Phoenix可谓是一对黄金搭档。HBase以其高效的列式存储和强大的数据扩展能力&#xff0c;成为大数据存储领域的佼佼者&#xff1b;而Phoenix则以其SQL化的操作方式&#xff0c;简化了对HBase的访问过程。今天&#xff0c;就让我们一起看看如…

Pandas部分应掌握的重要知识点

目录 Pandas部分应掌握的重要知识点一、DataFrame数据框的创建1、直接基于二维数据创建&#xff08;同时使用index和columns参数&#xff09;2、基于excel文件中的数据来创建 二、查看数据框中的数据和联机帮助信息1、查看特殊行的数据2、查看联机帮助的两种常见方法&#xff0…

image with CV

""" 视觉&#xff1a;基本API应用&#xff08;OPENCV&#xff09; """ import cv2 import numpy as np"""图像读取方式3. 1.cv2.imread(filename or path, flags)flags0:灰度图像&#xff1b;flags1表示RGB图像&#xff1b;fl…

2024年mathorcup(妈妈杯)数学建模C题思路-物流网络分拣中心货量预测及人员排班

# 1 赛题 C 题 物流网络分拣中心货量预测及人员排班 电商物流网络在订单履约中由多个环节组成&#xff0c;图 ’ 是一个简化的物流 网络示意图。其中&#xff0c;分拣中心作为网络的中间环节&#xff0c;需要将包裹按照不同 流向进行分拣并发往下一个场地&#xff0c;最终使包裹…

《黑马点评》Redis高并发项目实战笔记(上)P1~P43

P1 Redis企业实战课程介绍 P2 短信登录 导入黑马点评项目 首先在数据库连接下新建一个数据库hmdp&#xff0c;然后右键hmdp下的表&#xff0c;选择运行SQL文件&#xff0c;然后指定运行文件hmdp.sql即可&#xff08;建议MySQL的版本在5.7及以上&#xff09;&#xff1a; 下面这…

ArrayList部分底层源码分析

JDK版本为1.8.0_271&#xff0c;以插入和删除元素为例&#xff0c;部分源码如下&#xff1a; // 部分属性 transient Object[] elementData; // 底层数组 private int size; // 记录元素个数 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA {}; // 空Obje…