【分块+斜率优化】loj6546. 简单的数列题

一道很有意思的分块+斜率优化,脑残康复计划。

题目描述

给定两个长度为n的数列 a和 b,有 m 个操作,操作分为三类 $1. \ l \ r \ w \ $:将数列$[l,r]$内所有数加上$w$ $2.\ x \ y$交换$ b_x \ b_y $ $3.\ l \ r $ 求 $ max: { a_i * b_i } {l \le i \le r} $

输入格式

输入第一行包含两个整数 n,m . 接下来一行包含 n 个整数 a_i 接下来一行包含 n 个整数 b_i 接下来 m 行,每行包含一个操作,具体见描述。 保证 $1\le n, 1\le x,y \le n $.

输出格式

对于每一个操作 3,输出一个整数表示询问答案。

样例

输入
5 3
1 2 4 5 9
5 2 3 2 1
1 2 3 3
2 3 4
3 2 5
输出
15
1≤n,m≤10^5, 0≤a i≤10^7, 0≤bi≤10^5, 0≤wi≤100 线段树不好操作?考虑分块 其实我们比较需要考虑的是在区间加的时候如何维护最大值位置。我们发现增加数是保证非负的。 由于对于一个元素的权值是$ w_i = lazy * b_i + c_i $ (ci表示bi * ai ) 我们注意到这个和一次函数很像,可以考虑到斜率优化 我们移下项 $ c_i = -lazy * b_i + w_i $ 也就是说,在一个块内,我们将-lazy看做斜率(斜率单调下降),将b看做横坐标,c看做纵坐标,那么求块内最大w_i,就是斜率为-lazy的直线穿过块内的点,可以得到的最大截距。可以想到由于这个斜率始终为非正的并且单调减小,那么斜线应该越变越陡峭的情况下,我们想得到最大截距,就应该在一个上凸的凸壳上求切点,并且切点显然应该横坐标单调增加。 这样我们每次重构块的时候都重新构造一遍上凸壳,并且求出切点的位置。对于查询,非整块部分暴力查询,整块部分的最大值位置我们已经处理好了。对于1号修改,非整块部分暴力查询并且重构,整块部分打lazy标记之后单调地移动最大值的位置(保证横坐标增加),2号修改直接交换两个bi并且暴力重构两个块就好了。 如果我们块设定大小为S,那么一次操作时间复杂度n/S(整块部分) + SlogS (暴力重构部分) 有数学大佬帮忙分析S应该取多大吗?。。。反正肯定不能直接暴力取根号,不然时间复杂度是n\sqrt(n) * log2(s) 打个表看下哪个最好,我取的$\sqrt{(n/log(n))}$ 貌似1218算出是110...... 时间复杂度O( m *n/S + SlogS) ) code:
#include<stdio.h>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#define int long long
using namespace std;

int n,m;
struct seg{
    int a,b,id;
}z[200005];int st[1505][105];
int L[1505],R[1505],KS,FK,laz[1505],blo[200005],dy[200005],top[1505],QD[1505];
bool cmp(seg aa,seg bb) {
    if(aa.b!=bb.b) return aa.b < bb.b;
    return aa.a < bb.a;
}
void rebuild(int x) {
    #define nw z[i]
    #define tp z[st[x][top[x]]]
    #define la z[st[x][top[x]-1]]
    #define qd z[st[x][QD[x]]]
    #define nqd z[st[x][QD[x]+1]]
    int lk = (x-1)*FK+1; int rk = min(n,x*FK);
    for(int i=lk;i<=rk;i++) z[i].a+=laz[x]; laz[x]=0;
    sort(z+lk,z+rk+1,cmp); top[x] = 0;
    for(int i=lk;i<=rk;i++) {
        dy[z[i].id] = i;
        while( (top[x]>1) && (nw.a-tp.a)*(tp.b-la.b) >= (nw.b-tp.b)*(tp.a-la.a) ) top[x]--;
        st[x][++top[x]] = i;
    }
    QD[x] = 1; while(QD[x]<top[x]&&qd.a*qd.b<=nqd.a*nqd.b) QD[x]++;
    #undef nw
    #undef tp
    #undef la
    #undef qd
    #undef nqd
}
void change(int x,int y,int w) {
    int lb = blo[x]; int rb = blo[y];
    if(lb==rb) {
        for(int i=x;i<=y;i++) z[dy[i]].a+=w;
         rebuild(lb);
         return;
    }
    for(int i=x;i<=lb*FK;i++) z[dy[i]].a+=w; 
    for(int i=(rb-1)*FK+1;i<=y;i++) z[dy[i]].a+=w;
    rebuild(lb); rebuild(rb);
    for(int i=lb+1;i<=rb-1;i++) {
        laz[i]+=w;
        while(QD[i]<top[i]&& (z[st[i][QD[i]]].a+laz[i])*z[st[i][QD[i]]].b < (z[st[i][QD[i]+1]].a+laz[i])*z[st[i][QD[i]+1]].b ) QD[i]++;
    }
}
void gaoswap(int x,int y) {
    swap(z[dy[x]].b,z[dy[y]].b);
    if(blo[x]==blo[y]) rebuild(blo[x]);
    else rebuild(blo[x]),rebuild(blo[y]);
}
int query(int x,int y) {
    int lb = blo[x]; int rb = blo[y];
    int ans = 0;
    if(lb==rb) {
        for(int i=x;i<=y;i++) ans = max(ans,(z[dy[i]].a+laz[lb])*z[dy[i]].b );
        return ans;
    }
    for(int i=x;i<=lb*FK;i++) {
        ans = max(ans,(z[dy[i]].a+laz[lb])*z[dy[i]].b);
    }
    for(int i=(rb-1)*FK+1;i<=y;i++) {
        ans = max(ans,(z[dy[i]].a+laz[rb])*z[dy[i]].b);
    }
    for(int i=lb+1;i<=rb-1;i++) {
        ans = max(ans,(z[st[i][QD[i]]].a+laz[i])*z[st[i][QD[i]]].b);
    }
    return ans;
}
main() {
//  freopen("3.in","r",stdin);
    //freopen("oo.in","w",stdout);
    scanf("%lld%lld",&n,&m);
    FK = sqrt(1.0*n/log2(n));
    KS = n/FK + (!n%FK);
    for(int i=1;i<=n;i++) scanf("%lld",&z[i].a),z[i].id=i;
    for(int i=1,j=1;i<=n;i++) {
        scanf("%lld",&z[i].b);
        blo[i] = j;
        if(i%FK==0) j++;
    }
    for(int i=1;i<=KS;i++) rebuild(i);
    int opt,x,y,w;
    for(int i=1;i<=m;i++) {
        scanf("%lld",&opt);
        if(opt==1) {
            scanf("%lld%lld%lld",&x,&y,&w);
            change(x,y,w);
        } else if(opt==2) {
            scanf("%lld%lld",&x,&y);
            gaoswap(x,y);
        } else {
            scanf("%lld%lld",&x,&y);
            printf("%lld\n",query(x,y));
        }
    }
}
posted @ 2019-02-20 07:57  Newuser233  阅读(7)  评论(0)    收藏  举报