• 【BZOJ2122】工作评估(分块)


    题目链接

    • 给定两个长度为 \(n\) 的序列 \(b_{1\sim n}\)\(c_{1\sim n}\)
    • 定义 \(h_a(x,y)=\begin{cases}a&y=x-1,\\\min\{h_a(x,y-1)+b_y,c_y\}&y\ge x\end{cases}\)
    • \(q\) 次询问,每次给定 \(l,r,a\),求 \(\max_{l\le x\le y\le r}h_a(x,y)\)
    • \(1\le n,m\le5\times10^4\)\(0\le a_i\le10^5\)\(|b_i|\le 10^4\)

    \(f(x,y,v)\)

    定义 \(f(x,y,v)\) 表示一个初始值为 \(v\) 的数在经过 \([x,y]\) 中的操作后将得到的值(操作指先加 \(b_i\),再向 \(c_i\)\(\min\))。

    首先有一个显然的性质:若 \(v_1 < v_2\),则 \(f(x,y,v_1)\le f(x,y,v_2)\)。因为更大的数代进去肯定不会使答案变小。

    其次,可以发现这个过程中无非两种情况:

    • 曾经向某个 \(c_i\)\(\min\) 过。则最终得到的值就相当于 \(c_i\) 经过 \([i+1,y]\) 中的操作后的值,与 \(v\) 无关。故此时的取值就等于 \(f(x,y,INF)\)
    • 不曾向任何 \(c_i\)\(\min\) 过。则 \(f(x,y,v)=v+\sum_{i=x}^yb_i\)

    如果向 \(c\)\(\min\) 过,则 \(v+\sum_{i=x}^yb_i\) 一定大于 \(f(x,y,INF)\);反之,若不曾取 \(\min\)\(v+\sum_{i=x}^yb_i\) 一定小于 \(f(x,y,INF)\)

    也就是说,\(f(x,y,v)=\min\{f(x,y,INF),v+\sum_{i=x}^yb_i\}\)

    其中 \(f(x,y,INF)\)\(\sum_{i=x}^yb_i\)\(x,y\) 确定时都是已知的(不妨分别记作 \(g\)\(s\)),也就是说 \(f(x,y,v)=\min\{g,v+s\}\)

    分块处理+二分求值

    对于每个块,我们直接抠出所有区间,分别求出它们的 \(g,s\)

    显然,如果一个区间 \(g,s\) 全大于等于另一个区间的 \(g,s\),那么后者就是一个无用的区间。

    将那些有用的区间按 \(g\) 升序,那么也就按 \(s\) 降序。

    每次询问代入一个 \(v\) 得到的最大的 \(f(x,y,v)\),只需要二分找到 \(g,v+s\) 大小关系发生变化的位置 \(x\)。则小于等于 \(x\) 的部分较小值都取 \(g\),在 \(x\) 处取最大值;大于 \(x\) 的部分较小值都取 \(v+s\),在 \(x+1\) 处最大值。因此只要比较这两个位置上的值,取较大的那个即可。

    这样就能求出块内答案。

    然后考虑块间答案,由于代入的值越大得到的值也就越大,所以我们只需要知道经过前面的部分能够得到的最大值。

    可能通过前面的最大值与当前块的一段前缀操作得到答案,只要在预处理时抠出每个块的所有前缀类似前面那样二分一下即可。

    新的最大值可能是前面的最大值经过当前块所有操作。但也可能是当前块的一段后缀,只要在预处理时抠出每个块的所有后缀类似前面那样二分一下即可。

    代码:\(O(n\sqrt n\log n)\)

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Rg register
    #define RI Rg int
    #define Cn const
    #define CI Cn int&
    #define I inline
    #define W while
    #define N 50000 
    #define SN 225
    using namespace std;
    int n,a0,nw,ans,sz,bl[N+5],b[N+5],c[N+5],t1[SN+5],t2[SN+5],t3[SN+5];
    struct S {int g,s;I bool operator < (Cn S& o) Cn {return g^o.g?g<o.g:s<o.s;}}w[SN+5],f[SN+5][N+5],Pre[SN+5][SN+5],Suf[SN+5][SN+5];
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
    	int ff,OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
    	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
    	Tp I void read(Ty& x) {x=0,ff=1;W(!isdigit(oc=tc())) ff=oc^'-'?1:-1;W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));x*=ff;}
    	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    	Tp I void writeln(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);pc('\n');}
    }using namespace FastIO;
    I void Work(S* f,int& t) {RI i,c=0;for(sort(f+1,f+t+1),i=1;i<=t;++i) {W(c&&f[c].s<=f[i].s) --c;f[++c]=f[i];}t=c;}//排序,删去无用部分
    I void Bd(CI o)//预处理
    {
    	RI l=(o-1)*sz+1,r=min(o*sz,n),i,j,g,s;
    	for(i=l;i<=r;++i) for(g=1e9,s=0,j=i;j<=r;++j) g=min(g+b[j],c[j]),s+=b[j],//维护g,s
    		f[o][++t1[o]]=(S){g,s},i==l&&(Pre[o][++t2[o]]=(S){g,s},0),j==r&&(Suf[o][++t3[o]]=(S){g,s},0),i==l&&j==r&&(w[o]=(S){g,s},0);//记录
    	Work(f[o],t1[o]),Work(Pre[o],t2[o]),Work(Suf[o],t3[o]);//预处理出所有区间/前缀/后缀
    }
    I void BF(CI l,CI r) {for(RI i=l;i<=r;++i) nw=min(max(nw,a0)+b[i],c[i]),ans=max(ans,nw);}//散块暴力
    I int Get(S* f,CI t,CI v) {RI l=0,r=t,mid;W(l^r) mid=l+r+1>>1,f[mid].g<v+f[mid].s?l=mid:r=mid-1;return max(l?f[l].g:0,l^t?v+f[l+1].s:0);}//二分求出代入v的最大值
    I void Qry(CI o) {ans=max(ans,Get(f[o],t1[o],a0)),ans=max(ans,Get(Pre[o],t2[o],max(nw,a0))),nw=max(min(w[o].g,nw+w[o].s),Get(Suf[o],t3[o],a0));}//整块
    I void Q(CI l,CI r) {RI L=bl[l],R=bl[r];if(L==R) return BF(l,r);BF(l,L*sz);for(RI i=L+1;i<R;++i) Qry(i);BF((R-1)*sz+1,r);}//询问
    int main()
    {
    	RI Qt,i;for(read(n,Qt),i=1;i<=n;++i) read(b[i]);for(i=1;i<=n;++i) read(c[i]);
    	for(sz=sqrt(n),i=1;i<=n;++i) bl[i]=(i-1)/sz+1;for(i=1;i<=bl[n];++i) Bd(i);
    	RI x,y;W(Qt--) read(x,y,a0),nw=a0,ans=0,Q(x,y),writeln(ans);return clear(),0;
    }
    
  • 相关阅读:
    PHP中有多态么
    【Android】九宫格实现
    采用xshell链路本地虚拟机Linux
    读取资源文件的工具.
    dede织梦背景经常使用标签
    PHP第三个教训 PHP基本数据类型
    Linux经常使用的命令(必看)
    易Android登录Demo
    [2013山东ACM]省赛 The number of steps (可能DP,数学期望)
    web开发性能优化---UI接口章
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ2122.html
Copyright © 2020-2023  润新知