【OJ3358】简单的数列题

给定两个长度为 \(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); 
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/farway17/p/10425636.html