给定两个长度为 \(n\) 的数列 \(a\) 和 \(b\),有 \(m\) 个操作,操作分为三类:
\(1\) \(l\) \(r\) \(w\) :将数列 \(a\) 中区间 \([l,r]\) 内所有数加上 \(w\) ;
\(2\) \(x\) \(y\) :交换 \(b_x\) 和 \(b_y\) ;
\(3\) \(l\) \(r\) : 求 \(\displaystyle \max_{i=l}^r \{a_i\cdot b_i\}\) .
\(1\le n,m\le 10^5,\ 0\le a_i\le 10^7,\ 0\le b_i\le 10^5,\ 0\le w_i\le 100\) .
考虑分块。每一块就直接维护 max{\(a_i\cdot b_i\)} .
然后我们看操作。第二个操作十分简单,直接交换后暴力重构即可。第一个操作区间修改,两边的块也可以直接修改。关键在于中间的块。
我们要求的元素的权值 \(w_i=cnt\cdot b_i+c_i\). ( \(cnt\) 为整块累加的值, \(c_i=a_i\cdot b_i\))
我们发现这其实是一个一次函数。我们对于每个 \(cnt\) 要找到最大的 \(w_i\) .
我们考虑对上面的式子变形,得到: \(c_i=-cnt\cdot b_i+w_i\).
我们要求的 \(w_i\) 即为斜率为 \(-cnt\) 的直线经过所有 \((b_i,c_i)\) ,与y轴的截距。显然最大截距的直线一定是凸壳的一条切线。同时我们发现随着 \(cnt\) 的增大,最大值的点的位置单调向右移动。
这样我们对于每一块按 \(b\) 值排序,然后维护一个上凸壳。每次整块增加时直接打标记,然后向右移动最大值位置。
单次修改复杂度为 $ \displaystyle\frac{n}{S}+S\log n$ , 取块大小 \(S\) 为 \(\displaystyle \sqrt{\frac{n}{\log n}}\) 复杂度最优为 \(O(\sqrt{n\log n})\)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define gc()(iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),(iS==iT?EOF:*iS++)):*iS++)
namespace io {
const int SIZE=(1<<21)+1;
char ibuf[SIZE],*iS,*iT,obuf[SIZE],*oS=obuf,*oT=oS+SIZE-1,c,qu[55]; int qr;
inline void flush(){
fwrite(obuf,1,oS-obuf,stdout);
oS=obuf;
}
inline void putc(char x){
*oS++ = x;
if(oS==oT) flush();
}
template <class I>
inline void gi (I &x){
for(c=gc();c<'0'||c>'9';c=gc());
for(x=0;c<='9'&&c>='0';c=gc()) x=(x<<1)+(x<<3)+(c&15);
}
template <class I>
inline void print(I x){
if (!x) putc('0'); if(x < 0) putc('-'),x=-x;
while(x) qu[++qr]=x%10+'0',x/=10;
while(qr) putc(qu[qr--]);
putc('\n');
}
struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io::gi;
using io::print;
const int N=100005,qN=1300;
struct node
{
ll a;
int b,id;
bool operator < (node x) const {
return b==x.b ? a<x.a : b<x.b;
}
} g[N];
int n,m,bel[N],k,s[qN][qN],tp[N],pos[N],br[N],p[N],b[N];
ll add[N];
#define top s[x][tp[x]]
#define dtp s[x][tp[x]-1]
#define Max(x) s[x][pos[x]]
#define ri register int
void build(int x)
{
for(ri i=br[x-1]+1;i<=br[x];++i) g[i].a+=add[x];
add[x]=pos[x]=tp[x]=0;
sort(g+br[x-1]+1,g+br[x]+1);
for(ri i=br[x-1]+1;i<=br[x];++i)
{
p[g[i].id]=i;
while(tp[x]>1&&(g[i].a*g[i].b-g[top].a*g[top].b)*(g[top].b-g[dtp].b)
>=(g[top].a*g[top].b-g[dtp].a*g[dtp].b)*(g[i].b-g[top].b))--tp[x];
s[x][++tp[x]]=i;
}
for(pos[x]=1;pos[x]<tp[x]&&g[s[x][pos[x]+1]].a*g[s[x][pos[x]+1]].b
>=g[s[x][pos[x]]].a*g[s[x][pos[x]]].b;pos[x]++);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("easyseq.in","r",stdin);
freopen("easyseq.out","w",stdout);
#endif
gi(n),gi(m);
int lg=0;for(;1<<lg+1<=n;++lg);
k=sqrt(n/lg);
for(ri i=1;i<=n;++i) bel[i]=(i-1)/k+1,gi(g[i].a);
for(ri i=1;i<=n;++i) gi(g[i].b),g[i].id=i;
for(ri i=1;i<=bel[n];++i) br[i]=min(n,i*k),build(i);
while(m--)
{
ri op,l,r; gi(op),gi(l),gi(r);
if(op==1)
{
ri x,y; gi(x);
for(;bel[l]==bel[l-1]&&l<=r;++l) g[p[l]].a+=x;
build(bel[l-1]);
if(l>r) continue;
for(y=bel[l];br[y]+1<=r;++y)
{
add[y]+=x;
for(;pos[y]<tp[y]&&(g[s[y][pos[y]+1]].a+add[y])*g[s[y][pos[y]+1]].b>=
(g[s[y][pos[y]]].a+add[y])*g[s[y][pos[y]]].b;pos[y]++);
}
for(l=(y-1)*k+1;l<=r;++l) g[p[l]].a+=x;
build(bel[r]);
}
if(op==2)
{
g[p[l]].b^=g[p[r]].b^=g[p[l]].b^=g[p[r]].b;
build(bel[l]),build(bel[r]);
}
if(op==3)
{
ll ans=0; ri y;
for(;bel[l]==bel[l-1]&&l<=r;++l)
ans=max(ans,(g[p[l]].a+add[bel[l]])*g[p[l]].b);
if(l>r) {
print(ans); continue;
}
for(y=bel[l];br[y]+1<=r;++y)
ans=max(ans,(g[Max(y)].a+add[y])*g[Max(y)].b);
for(l=(y-1)*k+1;l<=r;++l)
ans=max(ans,(g[p[l]].a+add[bel[l]])*g[p[l]].b);
print(ans);
}
}
}