简单的数列题

给定两个长度为 \(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); 
		}
	}
}
posted @ 2019-02-24 11:22  x_faraway_x  阅读(392)  评论(1编辑  收藏  举报