魔性の分块 | | jzoj1243 | | 线段树の暴力
题目的打开方式是酱紫的
然而作为一只蒻蒟根本不会线段树该怎么办呢?
sro MZX orz 是这样说的:用分块啊!
分块
根据紫萱学姐的教程,分块的打开姿势是这样的:
我们要对一个数组进行整体操作,那么我们就可以把他们分成元素相等的n部分,由于n部分的最大值很容易找,也就是我们可以预处理出最大值(更何况此题最开始数组赋初值为0)我们要查询第k1-k2个数的最大值,就返回k1-k2所对应的块的最大值即可,
好,作为一只蒻蒟根本不知所云?
用一张图解来表示一下就是酱紫
红线代表整个数组,底下数轴就代表每一块的大小,绿线表示查询的区间,蓝线和橙线代表块里的其他元素;
那么左端点块内剩余的元素该怎么找呢?
这时候我们可以模拟出来一个小块,这个小块代表剩余元素的最大值,然后再和其他元素块的最大值就可以了,同理右端点也是如此;
那么代码实现呢?
代码
莫名其妙刚开始只能过小数据,我也不知道为什么,后来经过神犇lyy的点拨,我才知道是什么意思
(一)插入
v-1.0的代码如下
1 2 3 4 5 6 | int tempx=x/S; int left=tempx*S,right=min(left+S,n); a[x]=y; for ( int i=left;i<right;i++) if (a[i]>block[tempx]) block[tempx]=a[i]; |
v2.0的代码如下
1 2 3 4 5 6 7 | int tempx=x/S; int left=tempx*S,right=min(left+S,n); //注意right的取值 a[x]=y; block[tempx]=-1*INF; for ( int i=left;i<right;i++) if (a[i]>block[tempx]) block[tempx]=a[i]; |
没错只有一步tempx的初值还要变化成最小值,并且要注意right中left+S不能超过n的取值范围
(二) 查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | int work( int x, int y) { int l=x/S,r=y/S,ans=-INF; //定位块 if (l==r) { //如果在一块内 for ( int i=x;i<=y;i++) if (a[i]>ans) ans=a[i]; return ans; } for ( int i=x,ed=(l+1)*S;i<ed;i++) if (a[i]>ans) ans=a[i]; for ( int i=l+1;i<r;i++) if (block[i]>ans) //整体操作 ans=block[i]; for ( int i=r*S;i<=y;i++) if (a[i]>ans) ans=a[i]; return ans; } |
posted on 2016-10-20 11:11 supersumax 阅读(286) 评论(0) 编辑 收藏 举报
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步