题目描述

二阶堂真红给了你一个长为n的序列a,有m次操作

1.把区间[l,r]中大于x的数减去x

2.查询区间[l,r]中x的出现次数

题解

做YNOI真**爽。。。

我们发现这道题的操作非常诡异,把大于x的数减去x。

想一想这个操作会带来什么,会使这个数列的极差减小x(如果有大于x的数的话)。

然后如果我们能以至多O(x)的代价是极差缩小x的话,那么它的总复杂度是不会超过O(n)的。

然后我们发现log数据结构没法维护这种东西。

于是就用到了分块,每个块中维护每种数字出现的最早位置,然后把相同的数用并查集并起来。

对于修改操作。

我们讨论一下,x-0和maxnum-x哪个大,x-0大的话,就把小于x的数加上x,并且打个标记。

否则就把大于x的减掉x,这个用并查集搞就好了。

边角直接暴力就好了,注意每次暴力之前要把所有数都搞成当前数字的值。

注意数组越界。。。

代码

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize ("Ofast")
#pragma GCC optimize ("Ofast","inline","unroll-loops")
#pragma GCC optimize ("no-stack-protector")
#include<cstdio>
#include<vector>
#include<cmath>
#include<cctype>
#define R register
#define N 100009
#define M 318
using namespace std;
typedef long long ll;
int n,m,n1,f[N],head[M][N],a[N],be[N],ma[M],la[M],cnt[N];
inline int rd(){
int x=;char c=getchar();
while(!isdigit(c)){c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return x;
}
int find(int x){return f[x]=f[x]==x?x:find(f[x]);}
inline int mn(const int &x,const int &y){
return x>y?y:x;
}
inline int mx(const int &x,const int &y){
return x>y?x:y;
}
inline void build(const int &x){
ma[x]=;
int maxn=mn(n,x*n1);
for(R int i=(x-)*n1+;i<=maxn;++i)cnt[i]=,f[i]=i;
for(R int i=(x-)*n1+;i<=maxn;++i){
ma[x]=mx(ma[x],a[i]);
if(!head[x][a[i]])head[x][a[i]]=i,cnt[i]=;else{f[i]=head[x][a[i]];cnt[head[x][a[i]]]++;}
}
}
inline void pushdown(const int &x){
int maxn=mn(n,x*n1);
for(R int i=(x-)*n1+;i<=maxn;++i)a[i]=a[find(i)],head[x][a[i]]=;
for(R int i=(x-)*n1+;i<=maxn;++i)a[i]-=la[x];la[x]=;
}
inline void upd(const int &x,const int &pre,const int &now){
ma[x]=mx(ma[x],now);
if(!head[x][now]){
head[x][now]=head[x][pre];head[x][pre]=;a[head[x][now]]=now;
return;
}
f[head[x][pre]]=head[x][now];cnt[head[x][now]]+=cnt[head[x][pre]];cnt[head[x][pre]]=;head[x][pre]=;
}
int main(){
n=rd();m=rd();int opt,l,r,x;n1=sqrt(n);
for(R int i=;i<=n;++i)be[i]=(i-)/n1+,f[i]=i,a[i]=rd();
for(R int i=;i<=be[n];++i)build(i);
while(m--){
opt=rd();l=rd();r=rd();x=rd();
if(opt==){
if(be[l]==be[r]){
pushdown(be[l]);
for(R int i=l;i<=r;++i)if(a[i]>x)a[i]-=x;
build(be[l]);
}
else{
pushdown(be[l]);pushdown(be[r]);
for(R int i=l;i<=be[l]*n1;++i)if(a[i]>x)a[i]-=x;
for(R int i=(be[r]-)*n1+;i<=r;++i)if(a[i]>x)a[i]-=x;
build(be[l]);build(be[r]);
for(int i=be[l]+;i<be[r];++i){
if(ma[i]-la[i]>*x){
for(R int j=la[i]+;j<=la[i]+x;++j)if(head[i][j])upd(i,j,j+x);
la[i]+=x;
}
else{
for(R int j=la[i]++x;j<=ma[i];++j)if(head[i][j])upd(i,j,j-x);
ma[i]=mn(ma[i],la[i]+x);
}
}
}
}
else{
int ans=;
if(be[l]==be[r]){
for(R int i=l;i<=r;++i)if(a[find(i)]-la[be[l]]==x)ans++;
}
else{
for(R int i=l;i<=be[l]*n1;++i)if(a[find(i)]-la[be[l]]==x)ans++;
for(R int i=(be[r]-)*n1+;i<=r;++i)if(a[find(i)]-la[be[r]]==x)ans++;
for(R int i=be[l]+;i<be[r];++i)if(x+la[i]<N)ans+=cnt[head[i][x+la[i]]];
}
printf("%d\n",ans);
}
}
return ;
}

[Ynoi2018]五彩斑斓的世界的更多相关文章

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

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

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

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

  3. 解题:由乃OI 2018 五彩斑斓的世界

    题面 写在前面的扯淡: 分块的总体学习告一段落,这算是分块集中学习的最后一题么:以后当然也可能会写,就是零零散散的题了=.= 在洛谷上搜ynoi发现好像只有这道题和 由乃OI 2018 未来日记 是分 ...

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

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

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

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

  6. NOIP前的刷题记录

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

  7. tricks - 思维

    编辑 目录 tricks 系列 随机的性质 bitmask 建图 最基本的 黑白染色 Kruskal重构树 并查集维护值域 带根号的数三元环 根号分治 调和级数哈希 多属性哈希 时光倒流 时光反复横跳 ...

  8. [Ynoi2018]未来日记

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

  9. ynoi2018

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

随机推荐

  1. 关于tomcat 配置时一闪而过的问题

    TOMCAT JAVA_HOME or JRE_HOME environment variable is not defined correctly 按照教程已经安装了JDK并设置好了JAVA_HOM ...

  2. codeforces#410C Mike and gcd problem

    题目:Mike and gcd problem 题意:给一个序列a1到an ,如果gcd(a1,a2,...an)≠1,给一种操作,可以使ai和ai+1分别变为(ai+ai+1)和(ai-ai+1); ...

  3. LeetCode算法题-Design HashSet(Java实现)

    这是悦乐书的第298次更新,第317篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第166题(顺位题号是705).不使用任何内建的hash表库设计一个hash集合,应包含 ...

  4. Docker的使用初探(一):常用指令说明

    目录 Docker的使用初探(一):常用指令说明 为什么要用Docker Docker的安装与简单使用 国内镜像加速 常用指令 Docker的使用初探(一):常用指令说明 前几个星期实践的了,再不记录 ...

  5. Vue项目中的RSA加解密

    前后端使用rsa加密:  一般是客户端初始化时访问登录服务时,服务端面动态生成一对RSA对,公钥传给客户端,客户端拿到后,用户输入密码后,点登录时用公钥加密返回给服务端,服务端用私钥解就行了 一.安装 ...

  6. JAVA常用API的总结(2)

    这篇是常用API的结束了,写完的话可以继续往后复习了. 1.基本类型包装类的介绍与相关代码实现 对于数据包装类的特点就是可以将基本数据类型与字符串来回切换,接下来我会通过介绍Integer类的形式,来 ...

  7. (三)Installation

    Elasticsearch requires at least Java 8. Specifically as of this writing, it is recommended that you ...

  8. 初学Kafka工作原理流程介绍

    Apache kafka 工作原理介绍 消息队列技术是分布式应用间交换信息的一种技术.消息队列可驻留在内存或磁盘上, 队列存储消息直到它们被应用程序读走.通过消息队列,应用程序可独立地执行--它们不需 ...

  9. spring中基于注解使用AOP

    本文内容:spring中如何使用注解实现面向切面编程,以及如何使用自定义注解. 一个场景 比如用户登录,每个请求发起之前都会判断用户是否登录,如果每个请求都去判断一次,那就重复地做了很多事情,只要是有 ...

  10. 微信小程序开发 (资料汇总,谁还没被坑过?希望助你绕过一些坑)

    最近帮人家做一个微信小程序,刚好想熟悉一下.由于牵扯到多用户使用系统,以及数据共享,所以自然架构选择了,客户端和服务器的方式. 后台服务器是windows server,后台程序是.Net  WebA ...