【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 暴力+分块+链表的更多相关文章

  1. 51nod 1471 小S的兴趣 | 分块 链表

    51nod 1471 小S的兴趣 题面 小S喜欢有趣的事.但是,每个人的兴趣都是独特的.小S热衷于自问自答.有一天,小S想出了一个问题. 有一个包含n个正整数的数组a和针对这个数组的几个问题.这些问题 ...

  2. CDOJ 1292 卿学姐种花 暴力 分块 线段树

    卿学姐种花 题目连接: http://acm.uestc.edu.cn/#/problem/show/1292 Description 众所周知,在喵哈哈村,有一个温柔善良的卿学姐. 卿学姐喜欢和她一 ...

  3. codevs5037 线段树练习4加强版(暴力分块)

    求大爷教线段树怎么写啊QAQ 只会写分块...一开始脑抽写成了O(NKlogN)还被CZL大爷嘲讽了一发T T f[i][j]表示在第i块中,模k为j的数有几个,然后每次修改的时候只需要打个标记,查询 ...

  4. Codeforces 455D 分块+链表

    题意: 给定一个长度为 N 的序列两种操作1 l r 将[l,r]的数向右循环移位 2 l r 询问[l,r]内有多少个数等于 k其中 N,Q≤105,ai≤N 强制在线 思路: 1. 每块用一个链表 ...

  5. cdoj1324暴力分块

    #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> ...

  6. [BZOJ4028][HAOI2015]公约数数列[分块+分析暴力]

    题意 题目链接 分析 首先明确 \(xor\) 运算和 \(\rm gcd\) 没有联系! 注意到一个数字取 \(\rm gcd\) 且保证每次取 \(\rm gcd\) 值都会变小的话,最多取 \( ...

  7. BZOJ 3343: 教主的魔法 [分块]【学习笔记】

    3343: 教主的魔法 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1172  Solved: 526[Submit][Status][Discus ...

  8. bzoj 4765 普通计算姬(树状数组 + 分块)

    http://www.lydsy.com/JudgeOnline/problem.php?id=4765 很nice的一道题啊(可能是因为卡了n久终于做出来了 题意就是给你一棵带点权的有根树,sum( ...

  9. LOJ 6281 数列分块入门 5

    简化版题意 给出一个长为n的数列,以及n个操作,操作涉及区间开方(每个数都向下取整),区间求和,保证所有数都为有符号32位正整数. N<=50000 Solution 首先我们先思考: 一个有符 ...

随机推荐

  1. The difference between the request time and the current time is too large.阿里云oss上传图片报错

    The difference between the request time and the current time is too large. 阿里云oss上传图片的时候报错如上, 解决办法,把 ...

  2. 【scala】 scala xml 处理(⑨)

    1.scala 处理xml 2. 获取属性 3.修改节点 4.遍历 5.模式匹配 6.命名空间 7.文件加载 import scala.xml._ /** * @author xwolf * @sin ...

  3. 【转载】springboot + swagger

    注:本文参考自 http://www.jianshu.com/p/0465a2b837d2 https://www.cnblogs.com/java-zhao/p/5348113.html swagg ...

  4. mysql asyn 实战

    创建configuration时,发现URLParser找不到,于是只能使用配置文件来,当然使用配置文件比使用URL初始化还要直观些 def configurationWithPassword = n ...

  5. css媒体查询移动优先和pc优先

    移动优先,默认你是用手机浏览该网页的,当你用pc浏览时,就会以min-width进行递增式媒体查询 <!DOCTYPE html> <html lang="en" ...

  6. IDEA maven项目下测试mybatis例子,使用mappper class或package引入mapper映射文件,总是报错Invalid bound statement(所有配置完全正确)

    困扰几个小时,终于查到解决办法及原因(可以直接到最后看解决方案) 环境就是用IDEA搭建的maven项目,主要jar包引入配置如下 <dependencies> <dependenc ...

  7. 文件完整性hash验证demo(python脚本)

    一个简单的文件完整性hash验证脚本 #!/usr/bin/env python # -*- coding: utf- -*- import os import hashlib import json ...

  8. PHP代码审计笔记--任意文件下载漏洞

    在文件下载操作中,文件名及路径由客户端传入的参数控制,并且未进行有效的过滤,导致用户可恶意下载任意文件.  0x01 客户端下载 常见于系统中存在文件(附件/文档等资源)下载的地方. 漏洞示例代码: ...

  9. Mac终端解压命令集合

    tar 解包:tar xvf FileName.tar 打包:tar cvf FileName.tar DirName (注:tar是打包,不是压缩!) ——————————————— .gz 解压1 ...

  10. Python系统编程笔记

    01. 进程与程序 编写完毕的代码,在没有运行的时候,称之为程序 正在运行着的代码,就称为进程 进程是系统分配资源的最小单位. 进程资源包括: 中间变量 代码 计数器 02. 通过os.fork()函 ...