题面

写在前面的扯淡:

分块的总体学习告一段落,这算是分块集中学习的最后一题么;以后当然也可能会写,就是零零散散的题了=。=

在洛谷上搜ynoi发现好像只有这道题和 由乃OI 2018 未来日记 是分块,久闻由乃OI之大名,就想试着写一写这道题(那道太毒了,写不了);结果一开始差点被吓跑了,不过最后还是硬着头皮写完了QAQ

“分块最重要的就是常数” — —shadowice1984

好像挺有道理的,分块从诞生之日起就是一个依靠你的决策而决定复杂度的算法(或思想),它不像什么高级的数据结构每块的写法都是基本固定的,复杂度有着严格的证明— —分块是个相对灵活的算法(所以也说它是一种思想)。举个例子:最简单的那种序列分块基本上复杂度都是$O(\frac{n^2}{size})$,$size$就是你自己决定的块大小,大家可能都知道块大小开$sqrt(n)$(当然这是均值不等式算出来的),但是有时候可能某个操作的常数非常大,把块大小适当地调整可能会跑的更快......但是当卡常超过一定的地步,算法就又失去了本身的意义和美感......算了我语言表达能力太差了,还是赶快写题解吧=。=

考虑到区间一个个查询修改非常慢,先用并查集把每块里相同的数字连到第一次出现的位置上,然后考虑修改操作$(l,r,v)$:

对于一个最大值$maxx$不超过$2*v$的块,我们直接修改,即把大于$v$而小于最大值的部分的每个数$x$用并查集连到$x-v$

对于一个最大值$maxx$大于$2*v$的块,我们反过来修改,把小于$v$的部分的每个数$x$连到$x+v$,同时在区间上打标记

为什么要这样做?

首先我们发现这两种修改方法本质是一样的

然后我们发现对于第一种修改我们每次动的数是$v$级别的,同时我们把最大值缩小了$v$

而对于第二种修改我们每次动的数是$maxx-v$级别的,在那个限制下其实还是$v$级别的,和上面的效率是一样的(注意我们是根据$maxx$分出两种情况的,这也是用到了分块的思想)

然后均摊复杂度就有保证了,当然你还需要卡常(其实卡常不是很厉害,我就用了烂大街的快读+快输+register跑过去问题不大,还有这题当年在CF上好像因为CF太快+优化+3s实现把暴力放过去了=。=)

 #include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=,Sq=,M=;
int a[N],ori[N],blo[N],ll[N],rr[N],aset[N];
int siz[N],maxx[Sq],laz[Sq],firs[Sq][N];
int n,m,t1,t2,t3,t4,sqr,cnt;
inline int read()
{
int ret=;
char ch=getchar();
while(!isdigit(ch))
ch=getchar();
while(isdigit(ch))
ret=(ret<<)+(ret<<)+(ch^),ch=getchar();
return ret;
}
void write(int x)
{
if(x>) write(x/);
putchar(x%+);
}
int finda(int x)
{
return (x==aset[x])?x:aset[x]=finda(aset[x]);
}
inline void rebuild(int b)//块重构
{
register int i;
for(i=ll[b];i<=rr[b];i++)
{
maxx[b]=max(maxx[b],a[i]);
firs[b][a[i]]=,aset[i]=i,siz[i]=;
}
for(i=ll[b];i<=rr[b];i++)//把每个数都并到第一次出现的位置
{
int &fir=firs[b][a[i]];
if(fir) siz[fir]+=siz[i],aset[i]=fir;
else fir=i,ori[i]=a[i];
}
}
inline void force(int b,int l,int r,int v)//大力重构
{
register int i;
for(i=ll[b];i<=rr[b];i++)
firs[b][a[i]=ori[finda(i)]]=;
for(i=l;i<=r;i++)
if(a[i]-laz[b]>v) a[i]-=v;
rebuild(b);
}
void change(int l,int r,int v)
{
register int i,j;
int b1=blo[l],b2=blo[r];
if(b1!=b2)
{
force(b1,l,rr[b1],v);
force(b2,ll[b2],r,v);
for(i=b1+;i<=b2-;i++)
if(maxx[i]-laz[i]<*v)//当最大值不超过2*v时,正常地修改
{
for(j=laz[i]+v+;j<=maxx[i];j++)
{
int &pos1=firs[i][j];
int &pos2=firs[i][j-v];
if(pos1)
{
if(pos2) siz[pos2]+=siz[pos1],aset[pos1]=pos2;
else pos2=pos1,ori[pos2]=j-v; pos1=;
}
}
maxx[i]=min(maxx[i],laz[i]+v);
}
else//否则反过来,把其余的数加上这个值并打标记
{
for(j=laz[i]+;j<=laz[i]+v;j++)
{
int &pos1=firs[i][j];
int &pos2=firs[i][j+v];
if(pos1)
{
if(pos2) siz[pos2]+=siz[pos1],aset[pos1]=pos2;
else pos2=pos1,ori[pos2]=j+v; pos1=;
}
}
laz[i]+=v;
}
}
else force(b1,l,r,v);
//修改的理论依据:对于第一种情况最大值在O(v)时间内减小了v,对于第二种情况最大值在O(max-v)减少了max-v,所以最终的均摊复杂度是O(1)的
//(虽然CF的官方题解这里写的是极差,但我觉得不太对,例如对233,235两个数来说,将大于234的数减去234后极差反而在增大)
}
int query(int l,int r,int v)//普通的查询
{
register int i;
int b1=blo[l],b2=blo[r],ret=;
if(b1!=b2)
{
for(i=l;i<=rr[b1];i++)
ret+=(ori[finda(i)]-laz[b1]==v);
for(i=ll[b2];i<=r;i++)
ret+=(ori[finda(i)]-laz[b2]==v);
for(i=b1+;i<=b2-;i++)
if(laz[i]+v<=M) ret+=siz[firs[i][laz[i]+v]];
}
else
for(i=l;i<=r;i++)
ret+=(ori[finda(i)]-laz[b1]==v);
return ret;
}
int main ()
{
register int i;
n=read(),m=read();
sqr=sqrt(n)+,ll[cnt=]=;
for(i=;i<=n;i++)
{
a[i]=read(),ori[i]=a[i];
aset[i]=i,blo[i]=(i-)/sqr+;
maxx[blo[i]]=max(maxx[blo[i]],a[i]);
if(i%sqr==) rr[cnt++]=i,ll[cnt]=i+;
}
rr[cnt]=n;
for(i=;i<=cnt;i++) rebuild(i);
for(i=;i<=m;i++)
{
t1=read(),t2=read(),t3=read(),t4=read();
if(t1==) change(t2,t3,t4); else printf("%d\n",query(t2,t3,t4));
}
return ;
}

解题:由乃OI 2018 五彩斑斓的世界的更多相关文章

  1. [bzoj 5143][Ynoi 2018]五彩斑斓的世界

    传送门 Descroption 给了你一个长为n的序列a,有m次操作 1.把区间[l,r]中大于x的数减去x 2.查询区间[l,r]中x的出现次数 Solution 分块 对于每个块,我们都分别维护: ...

  2. Solution -「Ynoi 2018」「洛谷 P4117」五彩斑斓的世界

    \(\mathcal{Description}\)   Link.   给定序列 \(\{a_n\}\),处理 \(m\) 次操作: 给定 \(l,r,x\),把 \([l,r]\) 内所有 \(&g ...

  3. [Ynoi2018]五彩斑斓的世界

    题目描述 二阶堂真红给了你一个长为n的序列a,有m次操作 1.把区间[l,r]中大于x的数减去x 2.查询区间[l,r]中x的出现次数 题解 做YNOI真**爽... 我们发现这道题的操作非常诡异,把 ...

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

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

  5. 解题:国家集训队 Crash 的文明世界

    题面 这种套着高次幂的统计问题一般都要用到第二类斯特林数和自然数幂的关系:$a^k=\sum\limits_{i=0}^{k}S_k^iC_a^i*i!$ 那么对于每个点$x$有: $ans_x=\s ...

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

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

  7. OI那些事——AFO

    \(OI\)那些事--\(AFO\) 世界上从此少了一个\(Oier\)也不会有人知道,也许只有某个人在某年某月某日翻到了Eternal 风度的博客才会发现:哇,这哥们怎么\(Noip\)就退役了 两 ...

  8. 世界500强ING集团顺利的敏捷转型之路

    案例背景 为什么银行要像灰狗一样快? 荷兰国际集团(ING),成立于1991年,主营业务银行与保险业务,在全球45个国家和地区拥有分支机构,总资产887亿欧元(2018),全球53,000多名员工,拥 ...

  9. NOIP前的刷题记录

    因为这几天要加油,懒得每篇都来写题解了,就这里记录一下加上一句话题解好了 P4071 [SDOI2016]排列计数   组合数+错排 loj 6217 扑克牌 暴力背包 P2511 [HAOI2008 ...

随机推荐

  1. 学习HTML 第一节.小试牛刀

    此贴并非教学,主要是自学笔记,所述内容只是些许个人学习心得的记录和备查积累,难以保证观点正确,也不一定能坚持完成. 如不幸到访,可能耽误您的时间,也难及时回复,贴主先此致歉.如偶有所得,相逢有缘,幸甚 ...

  2. sqlserver(2012)清理tempdb

    当数据库运行时间长了之后,tempdb变得特别大,几十G,受不了啊:当然我们知道重启 SQL Server服务的话,tempdb数据库会自动重新创建的,从而使 tempdb 回归到初始大小.但是这是生 ...

  3. mysql 无法启动,错误1067,进程意外终止

    在做项目启动mysql数据库时,经常出现 这个错误,今天总结一下 //查看了网上很多的方法,都不适用,但或许对你适用.ps:网上只提供了怎么解决这个问题,但是没有将怎么去发现问题,对症下药才是王道.而 ...

  4. Windows 下在 Python (Anaconda) 中安装 Dlib 库

    0. 引言 介绍在 Windows  操作系统下,在 Python 的 Anaconda 集成环境中,安装 Dlib 库 : 对于不了解源码编译的,或者利用 cmake 方法失败的,可以尝试下此方法: ...

  5. adb shell top 命令详解

    [?25l[0m[H[J 当前系统时间 Tasks: 552 total, 1 running, 510 sleeping, 0 stopped, 0 zombie 任务(进程) 系统现在共有552个 ...

  6. JAVA学习笔记--简介几个常见关键字static、final、this、super

    一.static static(静态的),可以放在类.方法.字段之前. 通常,当创建类时,就是在描述那个类的外观与行为.除非用 new 创建那个类的对象,否则,实际上并未获得任何对象.执行 new 来 ...

  7. 在Emacs 23里字体的调整(转自ChinaUnix.net)

    首先,在Emacs中,通过菜单Options --> Set Default Font,设置好你喜欢的字体. 然后,把光标放到你所在的字体上,用命令M-x describe-font来查看你当前 ...

  8. java-HttpGetPost-图片字节流上传

    在java程序开发中经常用到与服务端的交互工作,主要的就是传递相应的参数请求从而获取到对应的结果加以处理 可以使用Get请求与Post请求,注意!这里的Get请求不是通过浏览器界面而是在程序代码中设置 ...

  9. ES6的新特性(18)——async 函数

    async 函数 含义 ES2017 标准引入了 async 函数,使得异步操作变得更加方便. async 函数是什么?一句话,它就是 Generator 函数的语法糖. 前文有一个 Generato ...

  10. 调试和开发npm模块的方式

    ln -s(软连接) 假设my-project是运行npm模块的项目,vue-router是我们需要调试的npm模块 将vue-router下载到与my-project同级目录中. git clone ...