简单的数列题

给定两个长度为 (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_icdot b_i}) .

(1le n,mle 10^5, 0le a_ile 10^7, 0le b_ile 10^5, 0le w_ile 100) .


考虑分块。每一块就直接维护 (max {a_icdot b_i}) .

然后我们看操作。第二个操作十分简单,直接交换后暴力重构即可。第一个操作区间修改,两边的块也可以直接修改。关键在于中间的块。

我们要求的元素的权值 (w_i=cntcdot b_i+c_i). ( (cnt) 为整块累加的值, (c_i=a_icdot b_i))

我们发现这其实是一个一次函数。我们对于每个 (cnt) 要找到最大的 (w_i) .

我们考虑对上面的式子变形,得到: (c_i=-cntcdot b_i+w_i).

我们要求的 (w_i) 即为斜率为 (-cnt) 的直线经过所有 ((b_i,c_i)) ,与y轴的截距。显然最大截距的直线一定是凸壳的一条切线。同时我们发现随着 (cnt) 的增大,最大值的点的位置单调向右移动。

这样我们对于每一块按 (b) 值排序,然后维护一个上凸壳。每次整块增加时直接打标记,然后向右移动最大值位置。

单次修改复杂度为 $ displaystylefrac{n}{S}+Slog n$ , 取块大小 (S)(displaystyle sqrt{frac{n}{log n}}) 复杂度最优为 (O(sqrt{nlog 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('
');
	}
	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); 
		}
	}
}
原文地址:https://www.cnblogs.com/farway17/p/10425636.html