只要你不强制在线, 我就能分块.
——Reflash

就算你强制在线, 我还是要分块.
——Enzymii

今天做了一波舒老师的毒瘤题, T1据说很水但是没思路所以直接放掉了..
去看了看T2好像可以水不错的分数, 那就去做一下.

我们先把题目放一下: (画风很迷很迷 大家稍微忍一下 忍一下)



就很显然一道数据结构题... 本来想写线段树, 但是标记看上去好像并不怎么好维护, 看一下数据范围, \(n\leq100000\)? 那我们可以分块啊~
题目的输入格式中有一行小字说的是: "想用离线分块水过去? 不存在的" 然后成功被窝打脸...但其实用的是在线分块...

那么具体要怎么写呢? 我们看一下这些操作...
这里默认看下去的都知道基础的分块怎么写了哈~


我们先来看这个奇怪的修改操作.
我们接下来会各种用到
\[ \sum_{i=1}^xi=\frac{x(x+1)}2 \]
所以我们做一个宏定义就是偷个懒, 用一个\(s(x)\)来表示前x个正整数的和..

那么这个修改操作是等价于将区间\([L,R]\)中每个数\(X\)加\(s(X-L+1)\)的..

对于一次操作, 不满一个块的当然是暴力, 所以我们只需要考虑整块的情况.
我们令\(L\)编号为\(1\), \(R\)为\(R-L+1\), 这样每个点就相当于加了一个1到这个点编号的前缀和.
首先非常明确的是这个前缀和是可以O(1)求出的~
我们假设一个要处理的整块的左端点的编号为\(x\).

然后可以明确的是下一个点比它大\(x+1\), 再下一个点比前一个点大\(x+2\), 再后面是\(x+3\)... ,以此类推.
如果只是这样的话我们记录一下这个块的首项增加的数量(就是\(s(x)\)啦)(这东西我管它叫标记1), 和块左端点在操作区间的编号\(x\)(这个就叫标记2吧), 就可以\(O(1)\)推出每个点的实际值了...

但是我们要打的标记不止一个... 我们假设这个要处理的块之前的标号有一个\(x\)了, 我们要再加一个标号\(y\).
我们当然不能开个数组(vector)存每个标记, 就要考虑标记的合并问题.

我们可以先看块的左端点看出原来这个点的增加的值应该是\(s(x)\), 现在这个值要变成\(s(x)+s(y)\), 这个变化很容易, 我们把标记1更改下就行, 复杂度\(O(1)\)
同时后面的点要从\(s(x+1)\)变成\(s(x+1)+s(y+1)\)... 根据公式我们可以得出现在这一项比前一项大了\(x+y+2\).
那么以此类推再下一个点比前一个点大\(x+y+4\), 再然后是\(x+y+6\)...
我们发现\(x\)与\(y\)总是简单相加的, 所以标记2也可以直接相加.
但是我们发现常数项跟原来相比扩大了2倍... 所以大概也必须记录一下这个常数项.
但是常数项的规律我们还没完全摸透(比如我们无法确定是线性关系还是指数关系(但究竟什么关系不是很显然么))
那我们再加一个标号\(z\), 看一下变化.. 发现常数项变成了原来的3倍...
所以我们惊奇地发现, 这个常数项其实就是这个块加上的标号的个数, 我们再用一个标记维护这玩意就行了(叫标记3好了)

总结一下, 我们对每个完整的块维护四个标记:

  1. 块的首项增加的数
  2. 块左端点在当前操作区间的编号
  3. 块被操作区间完整包含的次数
  4. 还有一个最普通的, 不含特殊标记的区间和

当我们进行一次修改操作时, 对于不完整的块, 直接暴力修改单点值, 顺带维护标记4.
而对于每个完整的块, 设左端点在这个区间的编号为\(x\)的话:

  1. 标记1 +s(x)
  2. 标记2 +x
  3. 标记3 +1
    这样就维护完了.

我们再来看查询操作.
查询的时候, 对于不完整的块依然是暴力加和..
那么如何通过标记计算一个单点的值?

我们可以知道, 在这个点所在的块上, 维护着一堆标记来记录这个点增加了多少.
所以这个单点的值=基础值(就是暴力修改的时候改的值)+通过标记计算出的增加值.

我们通过上面的分析知道, 这个块的首项增加了[1]([x]表示标记x的值), 而这个块里的后一项比前一项要多[2]+[3]×(块内编号-1)..
综上可以得出
\[ now_i=a_i+([1]+[2]*(i-l)+[3]*s(i-l) \]
其中\(now\)表示最终结果, \(a\)表示基础值, \(l\)表示区间的左端点. 这样算是\(O(1)\)的, 就不会影响复杂度.

那么完整的块怎么算呢?
很像.. 我们只要对每一项都求和就行了.
\[ now_{bl}=sum_{bl}+[1]*blk+[2]*s(blk)+[3]*\sum_{i=1}^{blk-1}s(i) \]
其中后面的那一堆我们可以\(O(n)\)预处理... 所以计算起来也是\(O(1)\)的..

这样我们只要分\(\sqrt n\)大小的块, 就可以保证复杂度在\(O(q\sqrt n)\)了...

那么我们就做完了... 分块码起来还是比线段树简单些的...
像我码力这么弱的人要是写线段树考场上怕是完全debug不出来咯...

害怕舒老师卡我我还丧心病狂地压了一波常数(然而事实证明真的很难卡OvO), 于是代码变得很不好看... 大家凑合着看吧..

//不特别加注释了, 就说说数组的含义吧
//frt是标记1 adum是标记2 cnt是标记3 sum是标记4(基础数组区间和) a是基础数组
#include <cmath>
#include <cstdio>
#include <algorithm>
const int N=120020;
const int p=1e9+7;
const int M=1000;
int bl[N],frt[M],adum[M],sum[M],cnt[M],a[N];
int blk,n,type,q,last,l,r,blkk;
int mul[N],mmul[N];
inline int gn(int a=0,char c=0){for(;c<'0'||c>'9';c=getchar());for(;c>47&&c<58;c=getchar())a=a*10+c-'0';
return a;}
char swt[20];
inline void change(int l,int r){//为了压常数不择手段, 能不取模就不取模...register int i;if(bl[l]==bl[r]){for(i=l;i<=r;++i){a[i]+=mul[i-l+1]; if(a[i]>=p) a[i]-=p;sum[bl[i]]+=mul[i-l+1];if(sum[bl[i]]>=p) sum[bl[i]]-=p;}return;}int nxl=bl[l]*blk+1,endb=bl[r]-1,bll=nxl;for(i=l;i<nxl;++i){a[i]+=mul[i-l+1]; if(a[i]>=p) a[i]-=p;sum[bl[i]]+=mul[i-l+1];if(sum[bl[i]]>=p) sum[bl[i]]-=p;}for(i=(bl[r]-1)*blk+1;i<=r;++i){a[i]+=mul[i-l+1]; if(a[i]>=p) a[i]-=p;sum[bl[i]]+=mul[i-l+1];if(sum[bl[i]]>=p) sum[bl[i]]-=p;}for(i=bl[l]+1;i<=endb;++i,bll+=blk){frt[i]+=mul[bll-l+1]; if(frt[i]>=p) frt[i]-=p;++cnt[i]; adum[i]+=bll-l+1;if(adum[i]>=p) adum[i]-=p;}
}
inline int query(int l,int r,int ans=0){register int i;int nxl=bl[l]*blk+1,bll=nxl-blk,brl,endb=bl[r]-1;if(bl[l]==bl[r]){for(i=l;i<=r;++i){ans+=a[i]; if(ans>=p) ans-=p;ans+=frt[bl[l]]; if(ans>=p) ans-=p;ans+=1LL*(i-bll)*adum[bl[l]]%p; if(ans>=p) ans-=p;ans+=1LL*mul[i-bll]*cnt[bl[l]]%p; if(ans>=p) ans-=p;}return ans;}for(i=l;i<nxl;++i){ans+=a[i]; if(ans>=p) ans-=p;ans+=frt[bl[l]]; if(ans>=p) ans-=p;ans+=1LL*(i-bll)*adum[bl[l]]%p; if(ans>=p) ans-=p;ans+=1LL*mul[i-bll]*cnt[bl[l]]%p; if(ans>=p) ans-=p;}for(i=(bl[r]-1)*blk+1,brl=i;i<=r;++i){ans+=a[i]; if(ans>=p) ans-=p;ans+=frt[bl[r]]; if(ans>=p) ans-=p;ans+=1LL*(i-brl)*adum[bl[r]]%p; if(ans>=p) ans-=p;ans+=1LL*mul[i-brl]*cnt[bl[r]]%p; if(ans>=p) ans-=p;}for(i=bl[l]+1;i<=endb;++i){ans+=sum[i]; if(ans>=p) ans-=p;ans+=1LL*frt[i]*blk%p; if(ans>=p) ans-=p;ans+=1LL*mul[blk-1]*adum[i]%p; if(ans>=p) ans-=p;ans+=1LL*mmul[blk-1]*cnt[i]%p; if(ans>=p) ans-=p;}return ans;
}
int main(){freopen("stillmiss.in","r",stdin);freopen("stillmiss.out","w",stdout);    n=gn(); type=gn(); q=gn();blk=sqrt(n)+1;register int i;for(i=1;i<=n;++i){bl[i]=(i-1)/blk+1;mul[i]=1LL*i*(i+1)/2%p;mmul[i]=mmul[i-1]+mul[i];if(mmul[i]>=p) mmul[i]-=p;}while(q--){scanf("%s",swt);l=gn(),r=gn();if(type){l=(l+last-1)%n+1,r=(r+last-1)%n+1;if(l>r) std::swap(l,r);}if(swt[0]=='Q'){last=query(l,r);printf("%d\n",last);}else change(l,r);}
}

最后这道2s的题我倒是随便就艹过去了..
而且好像除了最后一组都是1~n这种卡分块的数据跑了1.014s, 前几个大数据点比std的\(O(nlogn)\)要快33%...

舒老师表示不开心... 可这跟我有什么关系吗?

分块大法好啊~

转载于:https://www.cnblogs.com/enzymii/p/8545677.html

【学术篇】规律选手再次证明自己(舒老师的胡策题 T2 LX还在迷路)相关推荐

  1. 舒老师AK的hu测 T2. LX还在迷路(线段树+等差数列)

    版权属于舒老师,想要引用此题(包括题面)的朋友请联系博主 分析: 这道题是舒老师的原创题(版权声明~) 神题啊,毒瘤题啊 正解 首先,我们可以先忽略n(n+1)2n(n+1)2n(n+1) \over ...

  2. 我的八年博士生涯(学术篇)

    点击上方"码农突围",马上关注 这里是码农充电第一站,回复"666",获取一份专属大礼包 真爱,请设置"星标"或点个"在看&quo ...

  3. 2018人工智能期末考试复习资料(一):学术篇

    机器之心知识委员会 机心通知函[2018]002号 2018 年人工智能专业期末考试复习资料:学术篇 各人工智能研究者.工程师.从业人: 2018 年是人工智能迅猛发展的一年,从技术研究到产业应用都取 ...

  4. 【学术篇】不知道该起啥标题了怎么办OvO

    题目是2017.11.07的一次胡策的三道题目- 这次胡策呢, 骄傲的只打暴力打了个垫底- solution出来之后呢, 又写了写.. 觉得应该纪念一下- 就这样吧= = ============== ...

  5. 对学术不怎么热爱,只想当大学老师而去读博可以么?

    链接:https://www.zhihu.com/question/397721200/answer/1306501096 编辑:深度学习与计算机视觉 声明:仅做学术分享,侵删 作者:小青柑 http ...

  6. 【学术】对学术不怎么热爱,只想当大学老师而去读博可以么?

    点击上方,选择星标或置顶,每天给你送干货! 阅读大概需要23分钟 跟随小博主,每天进步一丢丢 仅作学术分享,不代表本公众号立场,侵权联系删除 链接:https://www.zhihu.com/ques ...

  7. 舒老师AK的hu测 T1. 迷失沃尔玛(dp+贪心)

    版权属于舒老师,想要引用此题(包括题面)的朋友请联系博主 分析: mmp,这道题做了不短的时间(这是什么语法...) 首先我们可以用O(nlogn)O(nlogn)O(nlogn)的复杂度计算出f[i ...

  8. 荣耀magicwatch2鸿蒙,小猪搞机的评测 篇二十三:荣耀MagicWatch 2 上那些实用小功能盘点 功能还不是一般的丰富...

    小猪搞机的评测 篇二十三:荣耀MagicWatch 2 上那些实用小功能盘点 功能还不是一般的丰富 2019-12-19 19:56:18 4点赞 5收藏 4评论 荣耀MagicWatch 2 上那些 ...

  9. 学术前沿 | 规律与因果:大数据对社会科学研究冲击之反思

    推荐语:尽管方法都源于统计学,但同样是定量分析.经验研究,经济学与社会学在方法论上面存在显著的差异.在大数据时代,这两个"古老"的学科同时面临海量数据资源的冲击,大数据资源给两个学 ...

最新文章

  1. 三十一、MySQL 及 SQL 注入
  2. 【安全漏洞】ThinkPHP 3.2.3 漏洞复现
  3. EPG组合 (Exporter Prometheus Grafana) 监控MySQL
  4. HashCode和hashMap、hashTable
  5. 1073 多选题常见计分法 (20 分)
  6. 如何设置打印的时候不加上页面链接_excel表格的这10个打印小技巧,办公室财务人员记得收藏...
  7. 内存泄露和溢出的区别_Java 中的内存溢出和内存泄露是什么?我给你举个有味道的例子?...
  8. python爬虫之路——对斗破苍穹进行关键字提取,制作噪声云图
  9. linux常用命令之文件操作
  10. QQ音频文件服务器,unlock-music:支持解密网易云/QQ音乐的加密文件和ID3信息补全...
  11. java 坦克大战设计论文,java坦克大战毕业设计论文
  12. c语言编木马程序,5分钟教会!C语言远程控制木马:“控制端”制作,附送源码!...
  13. mysql 对中文排序_【MySQL】MySQL按中文排序
  14. redis 错误 Error reply to PING from master: '-DENIED Redis is running in protected mode because prote
  15. 关系抽取调研——工业界
  16. 用计算机做路由器,用笔记本做无线路由(笔记本电脑当无线路由器用怎么设置)...
  17. 2008上海英雄会,英雄如是说
  18. 地址解析 收货地址智能解析 已上传到Gitee上
  19. python--斗地主
  20. 【字源大挪移—读书笔记】 第一部分:字首

热门文章

  1. 在JFrame里画sin函数的图像
  2. C语言中的数字——水仙花数
  3. Linux 系统延时任务及定时任务
  4. 一图带你看懂什么是智慧城市
  5. 华为手环8添加门禁卡操作指导
  6. python读取图片进行对比
  7. Simulink中示波器图窗编辑设置
  8. IOS- Map简单地图应用
  9. ubuntu 通过命令行上传百度云
  10. MVVM框架及实现原理