【CF896E】Welcome home, Chtholly 暴力+分块+链表
【CF896E】Welcome home, Chtholly
题意:一个长度为n的序列ai,让你支持两种操作:
1.l r x:将[l,r]中ai>x的ai都减去x。
2.l r x:询问[l,r]中有多少ai=x。
n,m<=100000,ai,x<=100000。
题解:先分块,对于每一块,我们用双向链表维护块内所有不同的ai的值(排好序的);对于每个ai的值,我们再用一个链表维护这个值在块内所有的出现位置。
对于操作1,将所有ai>x的数都减去x 等价于 先将所有ai<=x的数都加上x,再将所有数减去x。那么对于两边的小块我们可以暴力重构,对于中间的大块我们讨论:
如果块内最大值>=2*x,那么取出所有<=x的数,将这些数+=x,再区间打标记,然后与剩下的数进行归并;
如果块内最大值<2*x,那么取出所有>x的数,将这些数-=x,然后与剩下的数进行归并。
这样的复杂度是多少呢?发现我们每次操作的复杂度与块内最大值的减少量是同阶的,因为每块的最大值最多从100000减到1,所以最终复杂度就是$O(n\sqrt {100000}+m\sqrt n)$的。
链表套链表。。。想想细节就多。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn=100010;
const int B=250;
int n,m,cnt,ans;
int sm[405],head[405],last[405],tag[405],bt[405][maxn],p[405],v[405],s[405][maxn];
int pre[maxn],nxt[maxn],siz[maxn],val[maxn],fs[maxn],ls[maxn];
int pv[maxn],nx[maxn];
queue<int> q;
inline void rebuild(int a,int b,int x,int i)
{
int j,k,u,lst;
for(cnt=0,j=head[i];j;j=nxt[j])
{
s[i][val[j]]=0,val[j]-=tag[i];
if(val[j]>x) for(k=fs[j];~k;k=nx[k]) if(k>=a&&k<=b)
{
p[++cnt]=k,v[cnt]=val[j]-x,siz[j]--;
if(pv[k]==-1) fs[j]=nx[k]; else nx[pv[k]]=nx[k];
if(nx[k]==-1) ls[j]=pv[k]; else pv[nx[k]]=pv[k];
}
if(!siz[j])
{
q.push(j);
if(!pre[j]) head[i]=nxt[j]; else nxt[pre[j]]=nxt[j];
if(!nxt[j]) last[i]=pre[j]; else pre[nxt[j]]=pre[j];
}
}
tag[i]=0;
for(lst=0,k=1,j=head[i];k<=cnt;k++)
{
for(;j&&val[j]<=v[k];lst=j,j=nxt[j]);
if(lst&&v[k]==val[lst]) u=p[k],pv[u]=ls[lst],nx[u]=-1,nx[ls[lst]]=u,ls[lst]=u,siz[lst]++;
else
{
u=q.front(),q.pop(),val[u]=v[k],fs[u]=ls[u]=p[k],pv[p[k]]=nx[p[k]]=-1,siz[u]=1;
pre[u]=lst;
if(!lst) nxt[u]=head[i],head[i]=u; else nxt[u]=nxt[lst],nxt[lst]=u;
if(!nxt[u]) last[i]=u; else pre[nxt[u]]=u;
lst=u;
}
}
for(j=head[i];j;j=nxt[j]) s[i][val[j]]+=siz[j];
}
inline void updata(int x,int i)
{
if(val[last[i]]-tag[i]<=x) return ;
int j,k,u,lst;
if(x+x<=val[last[i]]-tag[i])
{
for(cnt=0,j=head[i];j&&val[j]-tag[i]<=x;j=nxt[j]) p[++cnt]=j;
head[i]=j,pre[j]=0;
for(tag[i]+=x,k=1;k<=cnt;k++) u=p[k],s[i][val[u]]-=siz[u],val[u]+=x,s[i][val[u]]+=siz[u];
for(lst=0,k=1,j=head[i];k<=cnt;k++)
{
for(u=p[k];j&&val[j]<=val[u];lst=j,j=nxt[j]);
if(lst&&val[u]==val[lst])
pv[fs[u]]=ls[lst],nx[ls[lst]]=fs[u],ls[lst]=ls[u],siz[lst]+=siz[u],q.push(u);
else
{
pre[u]=lst;
if(!lst) nxt[u]=head[i],head[i]=u; else nxt[u]=nxt[lst],nxt[lst]=u;
if(!nxt[u]) last[i]=u; else pre[nxt[u]]=u;
lst=u;
}
}
}
else
{
for(cnt=0,j=last[i];j&&val[j]-tag[i]>x;j=pre[j]) p[++cnt]=j;
last[i]=j,nxt[j]=0;
for(k=1;k<=cnt;k++) u=p[k],s[i][val[u]]-=siz[u],val[u]-=x,s[i][val[u]]+=siz[u];
for(lst=0,k=1,j=last[i];k<=cnt;k++)
{
for(u=p[k];j&&val[j]>=val[u];lst=j,j=pre[j]);
if(lst&&val[u]==val[lst])
pv[fs[u]]=ls[lst],nx[ls[lst]]=fs[u],ls[lst]=ls[u],siz[lst]+=siz[u],q.push(u);
else
{
nxt[u]=lst;
if(!lst) pre[u]=last[i],last[i]=u; else pre[u]=pre[lst],pre[lst]=u;
if(!pre[u]) head[i]=u; else nxt[pre[u]]=u;
lst=u;
}
}
}
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar();
return ret*f;
}
int main()
{
//freopen("cf896E.in","r",stdin);
n=rd(),m=rd();
int i,j,k,lst,a,b,c,d,x;
memset(fs,-1,sizeof(fs)),memset(ls,-1,sizeof(ls));
memset(pv,-1,sizeof(pv)),memset(nx,-1,sizeof(nx));
for(i=1;i<=n;i++) q.push(i);
for(i=0;i<n;i++)
{
a=rd(),sm[i/B]=max(sm[i/B],a),s[i/B][a]++;
if(!bt[i/B][a]) b=bt[i/B][a]=q.front(),q.pop(),fs[b]=ls[b]=i,val[b]=a,siz[b]=1;
else b=bt[i/B][a],nx[ls[b]]=i,pv[i]=ls[b],ls[b]=i,siz[b]++;
}
for(i=0;i*B<n;i++)
{
for(lst=0,j=1;j<=sm[i];j++) if(bt[i][j])
{
a=bt[i][j],pre[a]=lst;
if(!lst) head[i]=a; else nxt[lst]=a;
lst=a;
}
last[i]=lst;
}
for(i=1;i<=m;i++)
{
if(rd()==1)
{
a=rd()-1,b=rd()-1,c=a/B,d=b/B,x=rd();
if(c==d) rebuild(a,b,x,c);
else
{
rebuild(a,b,x,c),rebuild(a,b,x,d);
for(j=c+1;j<d;j++) updata(x,j);
}
}
else
{
a=rd()-1,b=rd()-1,c=a/B,d=b/B,x=rd(),ans=0;
if(c==d)
{
for(j=head[c];j;j=nxt[j]) if(val[j]-tag[c]==x) for(k=fs[j];~k;k=nx[k]) if(k>=a&&k<=b) ans++;
}
else
{
for(j=head[c];j;j=nxt[j]) if(val[j]-tag[c]==x) for(k=fs[j];~k;k=nx[k]) if(k>=a&&k<=b) ans++;
for(j=head[d];j;j=nxt[j]) if(val[j]-tag[d]==x) for(k=fs[j];~k;k=nx[k]) if(k>=a&&k<=b) ans++;
for(j=c+1;j<d;j++) if(x+tag[j]<=val[last[j]]) ans+=s[j][x+tag[j]];
}
printf("%d\n",ans);
}
}
return 0;
}//8 13 75 85 88 100 105 120 122 128 1 1 8 70 1 3 8 3 1 2 4 10 1 2 7 27 2 1 5 5
【CF896E】Welcome home, Chtholly 暴力+分块+链表的更多相关文章
- 51nod 1471 小S的兴趣 | 分块 链表
51nod 1471 小S的兴趣 题面 小S喜欢有趣的事.但是,每个人的兴趣都是独特的.小S热衷于自问自答.有一天,小S想出了一个问题. 有一个包含n个正整数的数组a和针对这个数组的几个问题.这些问题 ...
- CDOJ 1292 卿学姐种花 暴力 分块 线段树
卿学姐种花 题目连接: http://acm.uestc.edu.cn/#/problem/show/1292 Description 众所周知,在喵哈哈村,有一个温柔善良的卿学姐. 卿学姐喜欢和她一 ...
- codevs5037 线段树练习4加强版(暴力分块)
求大爷教线段树怎么写啊QAQ 只会写分块...一开始脑抽写成了O(NKlogN)还被CZL大爷嘲讽了一发T T f[i][j]表示在第i块中,模k为j的数有几个,然后每次修改的时候只需要打个标记,查询 ...
- Codeforces 455D 分块+链表
题意: 给定一个长度为 N 的序列两种操作1 l r 将[l,r]的数向右循环移位 2 l r 询问[l,r]内有多少个数等于 k其中 N,Q≤105,ai≤N 强制在线 思路: 1. 每块用一个链表 ...
- cdoj1324暴力分块
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> ...
- [BZOJ4028][HAOI2015]公约数数列[分块+分析暴力]
题意 题目链接 分析 首先明确 \(xor\) 运算和 \(\rm gcd\) 没有联系! 注意到一个数字取 \(\rm gcd\) 且保证每次取 \(\rm gcd\) 值都会变小的话,最多取 \( ...
- BZOJ 3343: 教主的魔法 [分块]【学习笔记】
3343: 教主的魔法 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1172 Solved: 526[Submit][Status][Discus ...
- bzoj 4765 普通计算姬(树状数组 + 分块)
http://www.lydsy.com/JudgeOnline/problem.php?id=4765 很nice的一道题啊(可能是因为卡了n久终于做出来了 题意就是给你一棵带点权的有根树,sum( ...
- LOJ 6281 数列分块入门 5
简化版题意 给出一个长为n的数列,以及n个操作,操作涉及区间开方(每个数都向下取整),区间求和,保证所有数都为有符号32位正整数. N<=50000 Solution 首先我们先思考: 一个有符 ...
随机推荐
- QT中C++与Html端通信例子
C++(服务端)和HTML(客户端)通过websocket通信,通过qwebchannel.js实现 C++ -> HTML,通过信号. HTML -> C++,直接调用函数. Main函 ...
- VC++关于UNICODE版本的开发
关于UNICODE版本的开发 代码转换方案 概述 在VC6.0中,相应的有一些宏来代替ANSI的函数.宏或数据类型,这些宏在ANSI编译条件中处理字符串为单字节,而在UNICODE中处理字符串为双字节 ...
- Line云端全自动加好友机器人
一个 LINE 帐号可以加入 5,000 名好友,让这些 5,000 名好友收到 LINE 的主动提醒,好友会看到我的头像.主页照片.姓名与状态消息等,这种行为称为 LINE 的曝光. 如果我们要针对 ...
- create a cocos2d-x-3.0 project in Xcode
STEP1: Open Terminal SETP2: Run setup.py SETP3: Run source /Users/your_user/.bash_profile( so that e ...
- RHEL5 yum更新源
1.检查yum是否安装 rpm -qa |grep yum 2.利用CentOS的yum更新源来实现RHEL5的YUM功能 vi /etc/yum.repos.d/CentOS-Base.repo [ ...
- 8 -- 深入使用Spring -- 1...4 重写占位符配置器
8.1.5 重写占位符配置器 (PropertyOverrideConfigurer) PropertyOverrideConfigurer是Spring提供的另一个容器后处理器.PropertyOv ...
- ios开发之--armv7,armv7s,arm64,i386,x86_64详解
有时候在运行的时候,经常出现诸如i386的错误,最新一些可能会出现 No architectures to compile for (ONLY_ACTIVE_ARCH=YES, active arch ...
- backbone学习笔记:模型(Model)(1)基础知识
backbone为复杂Javascript应用程序提供MVC(Model View Controller)框架,框架里最基本的是Model(模型),它用来处理数据,对数据进行验证,完成后台数据与前台数 ...
- SaltStack 安装及配置认证
一.SaltStack 安装 SaltStack 是基于 Python 开发的,也是基于 C/S 架构,通过服务端 ( master ) 控制多台客户端 ( minion ) 实现批量操作这里我们使用 ...
- [XPath] XPath 与 lxml (二)XPath 语法
XPath 选取节点时使用的表达式是一种路径表达式.节点是通过路径(path)或者步(steps)来选取的. 本章使用以下 XML 文档作为示例. <?xml version="1.0 ...