P4117 [Ynoi2018] 五彩斑斓的世界

2024-04-09 04:20

本文主要是介绍P4117 [Ynoi2018] 五彩斑斓的世界,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

分析第一个操作

朴素的做法,遍历一遍大于x就-=x,极限复杂度O(mn)

分块做法

整块:我们维护一个最大值,从mx到x遍历一遍(减去x)用并查集操作merge(i,i-x),考虑mx=100001,x=1,极限复杂度O(mV)

我们可以分析

1.x>(mx/2),从mx到x遍历一遍,应该是最优的复杂度O(mx-x)

2.x<(mx/2),最优的复杂度应该是O(x),因此思考在这种情况下如何操作使得复杂度为O(x),从x到0遍历一遍呗,我们可以遍历一遍x到0,merge(i,i+x),打上区间减法标记

3.x==(mx/2)都行

通过势能分析法总复杂度应该是O(sqrt(n)V) (我母鸡)(操作让区间最大值和区间最小值的差值变小,,值域缩小)

考虑每次都是x==(mx/2),且mx==V,O(V/2*sqrt(m))?

散块:暴力操作,再重构,无脑真不错,每次最多重构O(2*sqrt(n)),总共O(m*sqrt(n))

分析第二个操作

整块:直接得到并查集的大小

散块:遍历l到r,查询并查集==x,res++;

分析总时间复杂度O(Vsqrt(n)+msqrt(n)),快O(1e9),卡卡常啦

如果这样操作我们应该需要一个O(V*sqrt(n))数组,开不下这么大的数组;

lxl这个trick很妙啊

因为我们块与块之间没有关系,且时间挺多,可以离线下来,答案还有可加性,所以我们可以计算每个块的贡献这样只要开O(V)的数组即可

因此空间复杂度是O(V),1e6随便开

接下来,我们用代码实现一下。。。

先分析一下我们定义哪些数据 

fa[N]并查集,index[V](存储该值的位置),val[N](存储该位置的值),num[V](存储该值的数量),lazy(减法懒标记),mx(最大值),ans[M](询问的答案)

int a[N];
int fa[N],index[V],num[V],val[N];//fa,该值的位置,大小,该位置的值
int L[B],R[B];//记录每个块的范围[l,r]
int ans[M];
int mx=-INF;
int lazy;//减法懒标记

L,R(设为全局变量也行)

并查集2个操作

1.find

inline int find(int x){if(fa[x]==x){return x;}return fa[x]=find(fa[x]);
}

2.merge

合并2个值的位置,2个值的数量,以及合并后要对原数组清空

inline void merge(int x,int y){if(index[y]){//值存在fa[index[x]]=index[y];//合并}else{//不存在index[y]=index[x];val[index[x]]=y;//赋值为y}num[y]+=num[x];//合并index[x]=0;//清空num[x]=0;//清空
}

重构

重新维护一遍之前的量

inline void rebuild(int pos){//记录最大值,合并值,处理值的数量 mx=-INF;lazy=0;for(int i=L[pos];i<=R[pos];i++){mx=max(mx,a[i]);if(!index[a[i]]){index[a[i]]=i;fa[i]=i;val[i]=a[i];}else{fa[i]=index[a[i]];}num[a[i]]++;}
}

操作一

1.整块

inline void modify(int x){//区间 O(V)if((x<<1)<=(mx-lazy)){//x*2<=mx,for(int i=lazy;i<=x+lazy;i++){//a[i]<=x 都加x,lazy+x;O(x);if(index[i]){merge(i,i+x);}}lazy+=x;}else{//2*x>mxfor(int i=mx;i>x+lazy;i--){//a[i]>x 减去x,O(mx-x);if(index[i]){merge(i,i-x);}}//最大的值可能有x,与原本的mx取小mx=min(mx,x+lazy);}
}

min解释一下(我一开始不会),现在的情况是2*x>mx,可以转化成x>mx-x

分析2种情况

1.mx>x && x(数组中存在x),x

2.mx<x,mx

因此要取min

2.散块

我们要只需要下传懒标记,操作完重构一下即可

inline void update(int l,int r,int x,int pos){//下传lazyfor(int i=L[pos];i<=R[pos];i++){int temp=val[find(i)];a[i]=temp-lazy;index[temp]=0;num[temp]=0;}for(int i=L[pos];i<=R[pos];i++){val[i]=0;}l=max(l,L[pos]);r=min(r,R[pos]);//暴力操作for(int i=l;i<=r;i++){if(a[i]>x){ a[i]-=x;}}rebuild(pos);
}

操作二

1.整块

直接加num[]

ans[j]+=num[que[j].x+lazy];

2.遍历一遍

inline int query(int l,int r,int x,int pos){int res=0;l=max(l,L[pos]);r=min(r,R[pos]);for(int i=l;i<=r;i++){if(val[find(i)]-lazy==x){res++;}}return res;
}

感觉询问比较轻松,主要是操作维护这块是难点

完整代码

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<vector>
#define INF 2147483647
using namespace std;
typedef long long ll;
const int N=1e6+9;
const int B=1e4+9;
const int V=1e5+9;
const int M=5e5+9;
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');}inline int max(int a,int b){if(a>b){return a;}return b;}inline int min(int a,int b){if(a>b){return b;}return a;}
}using namespace Lan;
int a[N];
int fa[N],index[V],num[V],val[N];//fa,该值的位置,大小,该位置的值
int L[B],R[B];//记录每个块的范围[l,r]
int ans[M];
int mx=-INF;
int lazy;//减法懒标记
struct Q{int op,l,r,x;
}que[M];
inline int find(int x){if(fa[x]==x){return x;}return fa[x]=find(fa[x]);
}
inline void merge(int x,int y){if(index[y]){//值存在fa[index[x]]=index[y];//合并}else{//不存在index[y]=index[x];val[index[x]]=y;//赋值为y}num[y]+=num[x];//合并index[x]=0;//清空num[x]=0;//清空
}
inline void rebuild(int pos){//记录最大值,合并值,处理值的数量 mx=-INF;lazy=0;for(int i=L[pos];i<=R[pos];i++){mx=max(mx,a[i]);if(!index[a[i]]){index[a[i]]=i;fa[i]=i;val[i]=a[i];}else{fa[i]=index[a[i]];}num[a[i]]++;}
}
inline void modify(int x){//区间 O(V)if((x<<1)<=(mx-lazy)){//x*2<=mx,for(int i=lazy;i<=x+lazy;i++){//a[i]<=x 都加x,lazy+x;O(x);if(index[i]){merge(i,i+x);}}lazy+=x;}else{//2*x>mxfor(int i=mx;i>x+lazy;i--){//a[i]>x 减去x,O(mx-x);if(index[i]){merge(i,i-x);}}//最大的值可能有x,与原本的mx取小mx=min(mx,x+lazy);}
}
inline int query(int l,int r,int x,int pos){int res=0;l=max(l,L[pos]);r=min(r,R[pos]);for(int i=l;i<=r;i++){if(val[find(i)]-lazy==x){res++;}}return res;
}
inline void update(int l,int r,int x,int pos){//下传lazyfor(int i=L[pos];i<=R[pos];i++){int temp=val[find(i)];a[i]=temp-lazy;index[temp]=0;num[temp]=0;}for(int i=L[pos];i<=R[pos];i++){val[i]=0;}l=max(l,L[pos]);r=min(r,R[pos]);//暴力操作for(int i=l;i<=r;i++){if(a[i]>x){ a[i]-=x;}}rebuild(pos);
}
inline void init(){mx=-INF;lazy=0;memset(num,0,sizeof(num));memset(index,0,sizeof(index));
}
inline bool inrange(int L,int R,int l,int r){//[l[L,R]r]return L>=l && R<=r;
}
inline bool outofrange(int L,int R,int l,int r){return L>r || l>R;
}
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();}for(int i=1;i<=m;i++){que[i].op=read();que[i].l=read();que[i].r=read();que[i].x=read();}int blo=sqrt(n);int t=ceil(n*1.0/blo);for(int i=1;i<=t;i++){L[i]=(i-1)*t+1;R[i]=i*t;}//逐块处理for(int i=1;i<=t;i++){init();rebuild(i);for(int j=1;j<=m;j++){if(que[j].l>que[j].r){continue;}if(outofrange(L[i],R[i],que[j].l,que[j].r)){//不在这个区间continue;}if(que[j].op==1){if(inrange(L[i],R[i],que[j].l,que[j].r)){//询问区间包含这个块modify(que[j].x);//整块处理}else{update(que[j].l,que[j].r,que[j].x,i);//这一块处理完重构}}else{if(que[j].x+lazy>1e5+1){//没有贡献 continue;}if(inrange(L[i],R[i],que[j].l,que[j].r)){//询问区间包含这一块ans[j]+=num[que[j].x+lazy];}else{ans[j]+=query(que[j].l,que[j].r,que[j].x,i);//只能处理这一块的}}}}for(int i=1;i<=m;i++){if(que[i].op==2){write(ans[i]);putchar('\n');}}return 0;
}

不愧是大分块,lxl orz,还是刷刷简单点的分块题再来挑战ynoi吧

无期稿件P4119 [Ynoi2018] 未来日记

这篇关于P4117 [Ynoi2018] 五彩斑斓的世界的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/887165

相关文章

揭秘世界上那些同时横跨两大洲的国家

我们在《世界人口过亿的一级行政区分布》盘点全球是那些人口过亿的一级行政区。 现在我们介绍五个横跨两州的国家,并整理七大洲和这些国家的KML矢量数据分析分享给大家,如果你需要这些数据,请在文末查看领取方式。 世界上横跨两大洲的国家 地球被分为七个大洲分别是亚洲、欧洲、北美洲、南美洲、非洲、大洋洲和南极洲。 七大洲示意图 其中,南极洲是无人居住的大陆,而其他六个大洲则孕育了众多国家和

简单的Q-learning|小明的一维世界(3)

简单的Q-learning|小明的一维世界(1) 简单的Q-learning|小明的一维世界(2) 一维的加速度世界 这个世界,小明只能控制自己的加速度,并且只能对加速度进行如下三种操作:增加1、减少1、或者不变。所以行动空间为: { u 1 = − 1 , u 2 = 0 , u 3 = 1 } \{u_1=-1, u_2=0, u_3=1\} {u1​=−1,u2​=0,u3​=1}

简单的Q-learning|小明的一维世界(2)

上篇介绍了小明的一维世界模型 、Q-learning的状态空间、行动空间、奖励函数、Q-table、Q table更新公式、以及从Q值导出策略的公式等。最后给出最简单的一维位置世界的Q-learning例子,从给出其状态空间、行动空间、以及稠密与稀疏两种奖励函数的设置方式。下面将继续深入,GO! 一维的速度世界 这个世界,小明只能控制自己的速度,并且只能对速度进行如下三种操作:增加1、减

【Linux】萌新看过来!一篇文章带你走进Linux世界

🚀个人主页:奋斗的小羊 🚀所属专栏:Linux 很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~ 目录 前言💥1、初识Linux💥1.1 什么是操作系统?💥1.2 各种操作系统对比💥1.3 现代Linux应用💥1.4 Linux常用版本 💥2、Linux 和 Windows 目录结构对比💥2.1 文件系统组织方式💥2.2

Elasticsearch:无状态世界中的数据安全

作者:来自 Elastic Henning Andersen 在最近的博客文章中,我们宣布了支持 Elastic Cloud Serverless 产品的无状态架构。通过将持久性保证和复制卸载到对象存储(例如 Amazon S3),我们获得了许多优势和简化。 从历史上看,Elasticsearch 依靠本地磁盘持久性来确保数据安全并处理陈旧或孤立的节点。在本博客中,我们将讨论无状态的数据持

【AI大模型应用开发】2.1 Function Calling连接外部世界 - 入门与实战(1)

Function Calling是大模型连接外部世界的通道,目前出现的插件(Plugins )、OpenAI的Actions、各个大模型平台中出现的tools工具集,其实都是Function Calling的范畴。时下大火的OpenAI的GPTs,原理就是使用了Function Calling,例如联网检索、code interpreter。 本文带大家了解下Function calling,看

005:VTK世界坐标系中的相机和物体

VTK医学图像处理---世界坐标系中的相机和物体 左侧是成像结果                                                    右侧是世界坐标系中的相机与被观察物体 目录 VTK医学图像处理---世界坐标系中的相机和物体 简介 1 在三维空间中添加坐标系 2 世界坐标系中的相机 3 世界坐标系中vtkImageData的参数 总结:

深入RabbitMQ世界:探索3种队列、4种交换机、7大工作模式及常见概念

文章目录 文章导图RabbitMQ架构及相关概念四大核心概念名词解读 七大工作模式及四大交换机类型0、前置了解-默认交换机DirectExchange1、简单模式(Simple Queue)-默认DirectExchange2、 工作队列模式(Work Queues)-默认DirectExchange3、发布/订阅模式(Publish/Subscribe)-FanoutExchange4、路

攻防世界 unseping

unseping 攻防世界web新手练习 -unseping_攻防世界web新手题unseping-CSDN博客 这道题对我来说还是有点难,什么oct绕过命令执行第一次遇到捏,所以基本是跟着别人的wp写的,一点点记录吧 先对源码进行分析 <?phphighlight_file(__FILE__);//定义了一个ease类class ease{private $method;privat

世界公认十大护眼灯数据出炉!一文看懂孩子用的台灯哪个牌子好

近年来,随着科技的迅猛发展,诸如智能手机、电脑等电子设备在工作、学习及娱乐中的应用日益广泛,人们对这些设备的依赖程度也随之加深。然而,长时间面对屏幕不可避免地给眼睛带来伤害,如眼疲劳、干燥甚至近视等问题。因此,市场对能够缓解眼疲劳的照明产品的需求日益增长。这类护眼照明产品通常采用无频闪、无紫外线辐射等技术,旨在减少对眼睛的潜在危害,有效保护视力健康,并降低眼疾的发生率。随着护眼台灯的不断创新进步,