zoukankan      html  css  js  c++  java
  • 洛谷P5073 [Ynoi2015] 世上最幸福的女孩

    线段树上维护最大子段和是在每个节点上维护四元组 ((mx,lm,rm,sum)),但现在有全局加操作,线段树就不能直接维护了。

    考虑如何维护 (lm)(rm) 同理,设 (pre(x)) 为长度为 (x) 的前缀和的值,(add) 为当前全局加的和,则 (add imes x + pre(x)) 是可能成为 (lm) 的值,将 ((x,pre(x))) 看作点对,能成为 (lm) 的点都在上凸包上,维护出上凸包后,在凸包上二分即可得到当前最值。

    发现 (mx) 维护时需要合并 (rm_{ls})(lm_{rs}),这里的合并即为闵可夫斯基和。

    若在凸包上二分,复杂度就为 (O(mlog^2n))。将询问离线,按全局加的值排序,即为询问的斜率单调增,直接在凸包上记录一个指针,就能做到 (O(mlog n)) 了。

    #include<bits/stdc++.h>
    #define maxn 1200010
    #define inf 100000000000000
    #define ls (cur<<1)
    #define rs (cur<<1|1)
    #define mid ((l+r)>>1)
    using namespace std;
    typedef long long ll;
    inline char gc()
    {
    	static char now[1<<20],*S,*T;
    	if(T==S)
        {
    		T=(S=now)+fread(now,1,1<<20,stdin);
    		if(T==S) return EOF;
    	}
    	return *S++;
    }
    inline int read()
    {
    	int x=0;char c=gc();bool flag=false;
    	while(!isdigit(c)){if(c=='-')flag=true;c=gc();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
    	return flag?-x:x;
    }
    template<typename F> inline void write(F x)
    {
       	short st[30],tp=0;
    	if(x<0) putchar('-'),x=-x;
    	do st[++tp]=x%10,x/=10; while(x);
    	while(tp) putchar('0'|st[tp--]);
        putchar('
    ');
    }
    int n,m,root=1,cnt;
    ll now;
    ll a[maxn],ans[maxn],sum[maxn];
    struct Ask
    {
        int l,r,id;
        ll v;
    }q[maxn];
    bool operator < (const Ask &a,const Ask &b)
    {
        return a.v<b.v;
    }
    struct Vec
    {
        ll x,y;
        Vec(ll a=0,ll b=0)
        {
            x=a,y=b;
        }
    };
    Vec operator + (const Vec &a,const Vec &b)
    {
        return Vec(a.x+b.x,a.y+b.y);
    }
    Vec operator - (const Vec &a,const Vec &b)
    {
        return Vec(a.x-b.x,a.y-b.y);
    }
    ll operator * (const Vec &a,const Vec &b)
    {
        return a.x*b.y-a.y*b.x;
    }
    vector<Vec> operator + (const vector<Vec> &a,const vector<Vec> &b)
    {
        vector<Vec> c;
        for(int i=0;i<a.size();++i) c.push_back(a[i]);
        for(int i=0;i<b.size();++i) c.push_back(b[i]);
        return c;
    }
    vector<Vec> operator + (const vector<Vec> &a,const Vec &b)
    {
        vector<Vec> c;
        for(int i=0;i<a.size();++i) c.push_back(a[i]+b);
        return c;
    }
    struct Convex
    {
        int pos;
        vector<Vec> p;
        void build()
        {
            if(p.size()<=2) return;
            int top=1;
            for(int i=2;i<p.size();++i)
            {
                while(top&&(p[i]-p[top-1])*(p[top]-p[top-1])<=0) top--;
                p[++top]=p[i];
            }
            while(p.size()>top+1) p.pop_back();
        }
        void init(ll v)
        {
            p.push_back(Vec(0,0)),p.push_back(Vec(1,v));
        }
        void update(Vec a)
        {
            p[a.x].y=max(p[a.x].y,a.y);
        }
        ll ask()
        {
            while(pos<p.size()-1&&now*p[pos].x+p[pos].y<=now*p[pos+1].x+p[pos+1].y) pos++;
            return now*p[pos].x+p[pos].y;
        }
    }mx[maxn],lm[maxn],rm[maxn];
    struct node
    {
        ll mx,lm,rm,sum;
        node(ll a=0,ll b=0,ll c=0,ll d=0)
        {
            mx=a,lm=b,rm=c,sum=d;
        }
    };
    node operator + (const node &a,const node &b)
    {
        return node(max(a.rm+b.lm,max(a.mx,b.mx)),max(a.lm,a.sum+b.lm),max(b.rm,b.sum+a.rm),a.sum+b.sum);
    }
    void merge(Convex &a,Convex &b,Convex &c)
    {
        int i=0,j=0;
        c.update(a.p[0]+b.p[0]);
        while(i<a.p.size()-1&&j<b.p.size()-1)
        {
            if((a.p[i+1]-a.p[i])*(b.p[j+1]-b.p[j])<=0) c.update(a.p[++i]+b.p[j]);
            else c.update(a.p[i]+b.p[++j]);
        }
        while(i<a.p.size()-1) c.update(a.p[++i]+b.p[j]);
        while(j<b.p.size()-1) c.update(a.p[i]+b.p[++j]);
    }
    void build(int l,int r,int cur)
    {
        if(l==r)
        {
            mx[cur].init(sum[cur]=a[l]),lm[cur].init(a[l]),rm[cur].init(a[l]);
            return;
        }
        build(l,mid,ls),build(mid+1,r,rs),sum[cur]=sum[ls]+sum[rs],mx[cur].p.push_back(Vec(0,0));
        lm[cur].p=lm[ls].p+(lm[rs].p+Vec(mid-l+1,sum[ls])),rm[cur].p=rm[rs].p+(rm[ls].p+Vec(r-mid,sum[rs]));
        for(int i=1;i<=r-l+1;++i) mx[cur].p.push_back(Vec(i,-inf));
        for(int i=0;i<mx[ls].p.size();++i) mx[cur].update(mx[ls].p[i]);
        for(int i=0;i<mx[rs].p.size();++i) mx[cur].update(mx[rs].p[i]);
        merge(rm[ls],lm[rs],mx[cur]),mx[cur].build(),lm[cur].build(),rm[cur].build();
    }
    node query(int L,int R,int l,int r,int cur)
    {
        if(L<=l&&R>=r) return node(mx[cur].ask(),lm[cur].ask(),rm[cur].ask(),sum[cur]+now*(r-l+1));
        if(R<=mid) return query(L,R,l,mid,ls);
        if(L>mid) return query(L,R,mid+1,r,rs);
        return query(L,R,l,mid,ls)+query(L,R,mid+1,r,rs);
    }
    int main()
    {
        n=read(),m=read();
        for(int i=1;i<=n;++i) a[i]=read();
        for(int i=1;i<=m;++i)
        {
            int opt,x;
            opt=read();
            if(opt==1) x=read(),now+=x,ans[i]=-1;
            else q[++cnt].v=now,q[cnt].l=read(),q[cnt].r=read(),q[cnt].id=i;
        }
        build(1,n,root),sort(q+1,q+cnt+1);
        for(int i=1;i<=cnt;++i) now=q[i].v,ans[q[i].id]=query(q[i].l,q[i].r,1,n,root).mx;
        for(int i=1;i<=m;++i)
            if(ans[i]!=-1)
                write(ans[i]);
        return 0;
    }
    
  • 相关阅读:
    js联系题目
    js运算符
    太极图
    第一周 Welcome
    对 vscode 自动格式化的结果不太满意,我们该如何自己调整直至自己满意为止
    ASP.NET MVC5.0 OutputCache不起效果
    对照实验(1)-批量清理系统临时文件
    ES6
    19.局部变量和全局变量
    18.函数定义和参数
  • 原文地址:https://www.cnblogs.com/lhm-/p/14161130.html
Copyright © 2011-2022 走看看