zoukankan      html  css  js  c++  java
  • P2496 [SDOI2012]体育课

    传送门

    分块

    对每个块维护一个 $add$ 和 $del$ 标记,对于块 $o$ 内某个位置 $i$,它真实的修改量为 $a[i]+add[o]*i-del[o]$

    这样就可以维护一个区间加一个等差数列的操作了

    对于操作 $2$,交换两个位置,直接把两个位置的块标记下传,然后直接交换

    对于操作 $1$,考虑到相同的块内 $add$ 只会越来越大,对于某个位置 $i$,它一开始是最大的位置,随着标记的增加,比它大的位置显然一定在它右边

    所以考虑维护一个数列,使得数列相邻两个位置中,一旦左边的被超越,下一个可能的最大值就是右边下一个

    我一开始天真地以为直接维护一个单调数列即可,然后搞了半天发现是错的,如图:

     对于这种情况,当 $a[j]$ 还没超过 $a[i]$ 时,$a[k]$ 可能已经超过 $a[i]$ 了,所以我们不能把 $a[j]$ 放到数列里,不然就无法保证单调性

    事实上,我们需要维护的是所有点对 $(x,a[x])$ 构成的上凸包,具体理由如下:

    对于某个位置 $i$,如果 $a[i]$ 被超越,那么对于下一个位置 $k$ ,$i,k$ 之间必须不存在 $j$,使得

    $a[i]+add*i-del>a[j]+add*j-del$ 并且 $a[k]+add*k-del>a[i]+add*i-del$

    即 $(a[i]-a[j])/(i-j)<-add$ 且 $(a[i]-a[k])/(i-k)>-add$

    即 $(a[i]-a[k])/(i-k)>(a[i]-a[j])/(i-j)$,发现左右两边其实就是连线的斜率,所以即维护一个上凸包

    具体实现起来还是有一些细节的

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<vector>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=2e5+7,M=357;
    int n,m;
    int bel[N],L[M],pos[M];
    ll a[N],add[M],del[M];
    vector <int> st[M];
    inline void push_down(int o)
    {
        for(int i=L[o];i<L[o+1];i++) a[i]+=add[o]*i-del[o];
        add[o]=del[o]=pos[o]=0; st[o].clear();
    }
    inline ll calc(int i,int o) { return a[i]+add[o]*i-del[o]; }
    inline void upd(int o)
    {
        while(pos[o]<st[o].size()-1 && calc(st[o][pos[o]],o)<=calc(st[o][pos[o]+1],o)  ) pos[o]++;
    }
    inline void build(int o)
    {
        for(int i=L[o];i<L[o+1];st[o].push_back(i),i++)
            while(st[o].size()>1 && 
            (a[i]-a[st[o][st[o].size()-1]])*(st[o][st[o].size()-1]-st[o][st[o].size()-2]) >=
            (a[st[o][st[o].size()-1]]-a[st[o][st[o].size()-2]])*(i-st[o][st[o].size()-1]) ) st[o].pop_back();
        upd(o);
    }
    inline void query(int l,int r)
    {
        int bl=bel[l-1]+1,br=bel[r+1]-1; ll res=0;
        if(bl>br)
        {
            for(int i=l;i<=r;i++) res=max(res, calc(i,bel[i]) );
            printf("%lld
    ",max(0ll,res-calc(1,1))); return;
        }
        for(int i=l;i<L[bl];i++) res=max(res, calc(i,bel[i]) );
        for(int i=L[br+1];i<=r;i++) res=max(res, calc(i,bel[i]) );
        for(int i=bl;i<=br;i++) res=max(res, calc(st[i][pos[i]],i) );
        printf("%lld
    ",max(0ll,res-calc(1,1)));
    }
    inline void Swap(int x,int y)
    {
        push_down(bel[x]); push_down(bel[y]);
        swap(a[x],a[y]);
        build(bel[x]); build(bel[y]);
    }
    inline void change(int l,int r,int t)
    {
        int bl=bel[l-1]+1,br=bel[r+1]-1;
        if(bl>br)
        {
            push_down(bel[l]); push_down(bel[r]);
            for(int i=l;i<=r;i++) a[i]+=1ll*(i-l+1)*t;
            build(bel[l]); build(bel[r]); return;
        }
        if(L[bl]!=l)
        {
            for(int i=l;i<L[bl];i++) a[i]+=1ll*(i-l+1)*t;
            push_down(bl-1); build(bl-1);
        }
        if(L[br+1]-1!=r)
        {
            for(int i=L[br+1];i<=r;i++) a[i]+=1ll*(i-l+1)*t;
            push_down(br+1); build(br+1);
        }
        for(int i=bl;i<=br;i++) add[i]+=t,del[i]+=1ll*(l-1)*t,upd(i);
    }
    int main()
    {
        n=read(),m=read(); int T=sqrt(n)+1;
        for(int i=1;i<=n;i++)
        {
            a[i]=read(); bel[i]=(i-1)/T+1;
            if(bel[i]!=bel[i-1]) L[bel[i]]=i;
        }
        bel[n+1]=bel[n]+1; L[bel[n+1]]=n+1;
        for(int i=1;i<=bel[n];i++) build(i);
        int opt,a,b;
        for(int i=1;i<=m;i++)
        {
            opt=read(); a=read(),b=read();
            if(opt==1) { query(a,b); continue; }
            if(opt==2) { Swap(a,b); continue; }
            change(a,b,read());
        }
        return 0;
    }
  • 相关阅读:
    使用 Spring data redis 结合 Spring cache 缓存数据配置
    Spring Web Flow 笔记
    Linux 定时实行一次任务命令
    css js 优化工具
    arch Failed to load module "intel"
    go 冒泡排序
    go (break goto continue)
    VirtualBox,Kernel driver not installed (rc=-1908)
    go运算符
    go iota
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11489575.html
Copyright © 2011-2022 走看看