把自己去年在luogu写的一个题解搬过来

原题解链接

1. 题目大意

给定一个长度为 \(n\) 的数列 \(a_1,a_2,a_3,...,a_n\) , 并给出 \(m\) 个操作,操作类型如下:

操作1:查询区间最大值,输出最大值与 \(a_1\) 的差;

操作2:交换两个数的位置;

操作3:选择一段区间 \([l,r]\) 并给定 \(t\) ,将区间中第 \(x\) 个数加上 $x\cdot t $ .

\(n,m \le 10^5\) .

2. 解题报告

本题的正解是分块。

首先我们先考虑操作3,对于两边的元素,我们直接暴力修改然后重构即可。那么我们如何维护整块呢?

维护 \(add[ x ]\) 表示第 \(x\) 块累加的 \(t\) , 那我们要得到单个元素,再维护一个偏移量 \(del[x]\) ,这样块中元素的权值即可表示为 \(w[i]=a[i]+add[x]\times i-del[x]\).

(举个例子,若给块 \([4,6]\) 加上 \(2T, 3T, 4T\) ,那么\(add[x]=T\) ,\(del[x]=2T\),这样 \(w[5]=a[5]+5T-2T=a[5]+3T\) .)

对于操作2,我们直接暴力交换然后重构块即可。

对于操作1,我们考虑在整块被修改后,如何维护块内的最大值。由于每个元素的编号 \(i\) 和权值 \(a_i\) 都是定值且 \(i\) 单增,我们可以将每个元素看成 \((i,a_i)\) ,然后用单调栈维护一个上凸壳。这样随着 \(add\) 的增大,最大元素位置一定向右移动,且元素权值呈单峰。

每个操作维护(询问)的复杂度都为 \(O( n\sqrt{n} )\),再加上本题时间限制宽松,可以轻松通过。

3. 参考程序

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace io {
const int SIZE=(1<<21)+1;
char ibuf[SIZE],*iS,*iT;
char gc()
{
if(iS==iT) iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin);
if(iS==iT) return EOF;
return *iS++;
}
inline int gi()
{
char c; int x=0,f=1;
for(;c<'0'||c>'9';c=gc())if(c=='-')f=-1;
for(;c>='0'&&c<='9';c=gc())x=(x<<1)+(x<<3)+c-'0';
return x*f;
}
}
using io::gi;
const int N=100005,qN=320;
int n,m,bel[N],b,s[qN][qN],tp[qN],pos[qN];
ll h[N],a[N],add[qN],del[qN];
#define top s[x][tp[x]]
#define dtp s[x][tp[x]-1]
#define Max(x) s[x][pos[x]]
void remove(int x)
{
for(int i=(x-1)*b+1;i<=x*b;i++) a[i]+=add[x]*i-del[x];
add[x]=del[x]=pos[x]=tp[x]=0;
}
void build(int x)
{
memset(s[x],0,sizeof(s[x]));
for(int i=(x-1)*b+1;i<=x*b;i++)
{
while(tp[x]>1&&(a[i]-a[top])*(top-dtp)>=(a[top]-a[dtp])*(i-top))--tp[x];
s[x][++tp[x]]=i;
}
for(pos[x]=1;pos[x]<=tp[x]&&a[s[x][pos[x]+1]]>=a[s[x][pos[x]]];pos[x]++);
}
void update(int x)
{
for(;pos[x]<=tp[x];pos[x]++)
if(a[s[x][pos[x]+1]]+add[x]*s[x][pos[x]+1]<a[s[x][pos[x]]]+add[x]*s[x][pos[x]])
break;
}
int main()
{
n=gi(),m=gi();
b=sqrt(n);
for(int i=1;i<=n;i++) bel[i]=(i-1)/b+1,a[i]=gi();
for(int i=1;i<=bel[n];i++) build(i);
while(m--)
{
int op=gi(),l=gi(),r=gi();
if(op==1)
{
ll k=a[1]+add[1]-del[1];
ll mx=k;
for(;bel[l]==bel[l-1]&&l<=r;l++)
mx=max(mx,a[l]+add[bel[l]]*l-del[bel[l]]);
for(;l+b<=r;l+=b)
mx=max(mx,a[Max(bel[l])]+add[bel[l]]*Max(bel[l])-del[bel[l]]);
for(;l<=r;l++)
mx=max(mx,a[l]+add[bel[l]]*l-del[bel[l]]);
printf("%lld\n",mx-k);
}
if(op==2)
{
remove(bel[l]),remove(bel[r]);
swap(a[l],a[r]);
build(bel[l]); build(bel[r]);
}
if(op==3)
{
int t=gi(),tl=l;
for(;bel[l]==bel[l-1]&&l<=r;l++) a[l]+=(l-tl+1)*t;
remove(bel[l-1]); build(bel[l-1]);
for(;l+b<=r;l+=b) add[bel[l]]+=t,del[bel[l]]+=(tl-1)*t,update(bel[l]);
for(;l<=r;l++) a[l]+=(l-tl+1)*t;
remove(bel[r]); build(bel[r]);
}
}
}

4. 附:维护上凸壳的正确性数学证明

附赠给不能理解维护上凸壳正确性的同学:

假设现在有3个元素 \(x,y,z\) ,设它们的编号分别为 \(h_x, h_y, h_z\),元素大小为 \(a_x,a_y,a_z\) ,权值为\(w_x,w_y,w_z\) , \(h_x<h_y<h_z\) 。设 \(add\) 值为 \(T\), 若存在 \(T\) 使得 \(w_y > w_x\) 且 \(w_y>w_z\),则作差列出不等式:

\(a_x-a_y<(h_y-h_x)T\) , \(a_y-a_z>(h_z-h_y)T\) .

两式整理合并可得 \(\displaystyle \frac{a_z-a_y}{h_z-h_y}<\frac{a_y-a_x}{h_y-h_x}\) .

即:直线 \(y\to z\) 的斜率小于直线 \(x\to y\) 的斜率,故维护上凸壳。同时易发现,随着 \(T\) 的不断增大,最大元素的位置右移,且最大元素左边的权值递增,右边的权值递减(即单峰)。

【Luogu2496】【BZOJ3005】[SDOI2012]体育课的更多相关文章

  1. P2496 [SDOI2012]体育课

    传送门 分块 对每个块维护一个 $add$ 和 $del$ 标记,对于块 $o$ 内某个位置 $i$,它真实的修改量为 $a[i]+add[o]*i-del[o]$ 这样就可以维护一个区间加一个等差数 ...

  2. BZOJ 2705: [SDOI2012]Longge的问题 [欧拉函数]

    2705: [SDOI2012]Longge的问题 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 2553  Solved: 1565[Submit][ ...

  3. BZOJ 2705: [SDOI2012]Longge的问题

    2705: [SDOI2012]Longge的问题 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 2554  Solved: 1566[Submit][ ...

  4. 【BZOJ】【2705】【SDOI2012】Longge的问题

    欧拉函数/狄利克雷卷积/积性函数 2705: [SDOI2012]Longge的问题 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1275  Solv ...

  5. BZOJ 2705: [SDOI2012]Longge的问题 GCD

    2705: [SDOI2012]Longge的问题 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnl ...

  6. bzoj 2706: [SDOI2012]棋盘覆盖 Dancing Link

    2706: [SDOI2012]棋盘覆盖 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 255  Solved: 77[Submit][Status] ...

  7. bzoj 2705: [SDOI2012]Longge的问题 歐拉函數

    2705: [SDOI2012]Longge的问题 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1035  Solved: 669[Submit][S ...

  8. Bzoj 2705: [SDOI2012]Longge的问题 欧拉函数,数论

    2705: [SDOI2012]Longge的问题 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 1959  Solved: 1229[Submit][ ...

  9. BZOJ 2726: [SDOI2012]任务安排( dp + cdq分治 )

    考虑每批任务对后面任务都有贡献, dp(i) = min( dp(j) + F(i) * (T(i) - T(j) + S) ) (i < j <= N)  F, T均为后缀和. 与j有关 ...

随机推荐

  1. 关于java继承条件下的构造方法调用

    首先是测试代码: class Grandparent { public Grandparent() { System.out.println("GrandParent Created.&qu ...

  2. JAVA web课堂测试1

    1登录账号:要求由6到12位字母.数字.下划线组成,只有字母可以开头:(1分)2登录密码:要求显示“• ”或“*”表示输入位数,密码要求八位以上字母.数字组成.(1分)3性别:要求用单选框或下拉框实现 ...

  3. Failed to read candidate component class

    今天编程时遇到了Failed to read candidate component class 这个异常,查了好久终于发现了是因为jdk的版本不对,所以报了这个错.

  4. CSS各种小技巧

    /* *背景的透明度设置 */ -moz-opacity: 0.8; opacity:.80; filter: alpha(opacity=80); 待续...

  5. 折腾前端条形码(Barcode)扫描识别, 笔记

    barcode @zxing/library 方案 本地勉强把 Demo 在 React 里面跑通, 但是不好控制开始结束, API 不明确.实际识别率很低. 我是用手机屏幕放的条形码, 大概也有影响 ...

  6. selenium 参数设置-window.navigator.webdriver

    selenium 参数设置 selenium启动chrome基本上与真实环境类似,但有一些变量还是不一样,需要注意. 有些网站通过这些参数识别爬虫. window.navigator.webdrive ...

  7. 图像分割利用KMeans生成灰度图

    import numpy as np import PIL.Image as image from sklearn.cluster import KMeans def loadData(filePat ...

  8. 关于html的基本知识

    先上基本介绍图 HTML 简介 超文本标记语言 Hyper Text Markup Language 什么是标签(大多数标签) 尖括号包围.成对出现 开始标签,结束标签 元素 编辑器 HBuilder ...

  9. 浅谈区块链和p2p网络

    最近对区块链产生了兴趣就去了解了一下,分享一下.... 首先要先了解一下什么叫做区块链: 区块链:简单来说就是一种基于分布式数据存储.点对点传输.共识机制.加密算法等计算机技术的新型应用模式. 相信说 ...

  10. Mongodb - 解决 ( aggregate聚合管道 ) $match 根据 id 匹配 返回 [ ] 的问题

    需要对 id 进行转换 const mongoose = require('mongoose') var ObjectId = mongoose.Types.ObjectId;   await Use ...