Ynoi2013 D2T2

Link
看到最大子段和就要想到维护(sum,pre,suf,ans)四个信息。
考虑将序列分为(sqrt n)块,对于每一块内,总共只有(O(n))种不同的值域区间。
如果我们在每一块内,对每一种值域区间处理出整块的信息,那么就可以在(O(nsqrt n))的时间复杂度内求出素有询问的答案。
考虑对序列分治,分治底层的处理是trivial的,因此只需考虑如何合并([l,mid],(mid,r])的信息。
首先可以通过归并排序得到当前序列区间按权值升序排序后的数组。
然后假如我们要求当前序列区间值域区间为([L,R))答案,那么我们可以找到([L,R])([l,mid])((mid,r])序列区间中对应的等价的值域区间,然后直接合并得到答案。
利用单调指针预处理(forall iin[l,r],min{a_j|a_jge a_iwedge jin[l,mid]},min{a_j|a_jge a_iwedge jin(mid,r]})即可。
离线所有询问之后即做到复杂度(O(nsqrt n)+O(n))

#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
using i64=long long;
using std::max;
const int N=100007,B=260;
char ibuf[1<<23|1],*iS=ibuf;int n,m,L,R,it1,it2,a[N],h[N],r[N],rank[N],s[N];
int read(){int x=0,f=1;while(isspace(*iS))++iS;if(*iS=='-')f=-1,++iS;while(isdigit(*iS))(x*=10)+=*iS++&15;return f*x;}
struct data
{
    i64 sum,pre,suf,ans;
    data(){sum=pre=suf=ans=0;}
    data(i64 val){sum=val,pre=suf=ans=max(val,0ll);}
    data(i64 a,i64 b,i64 c,i64 d):sum(a),pre(b),suf(c),ans(d){}
}t[2*N];
data operator+(const data&l,const data&r){return data(l.sum+r.sum,max(l.pre,l.sum+r.pre),max(r.suf,r.sum+l.suf),max(max(l.ans,r.ans),l.suf+r.pre));}
struct node
{
    data*a;int*val,n;
    node(){}
    node(int N):a(t+it1),val(s+it2),n(N+1){it1+=n*n,it2+=n;}
    data&get(int x,int y){return a[x*n+y];}
    void init(int x){get(0,1)=data(x),get(0,0)=get(1,1)=data(),val[0]=x,val[1]=2e9;}
    void merge(node&ls,node&rs)
    {
	int*l=s+it2,*r=l+n;
	it2+=n+n,std::merge(ls.val,ls.val+ls.n-1,rs.val,rs.val+rs.n,val);
	for(int i=0,itl=0,itr=0;i<n;l[i]=itl,r[i]=itr,++i)
	{
	    for(;ls.val[itl]<val[i];++itl);
	    for(;rs.val[itr]<val[i];++itr);
	}
	for(int i=0;i<n;++i) for(int j=i;j<n;++j) get(i,j)=ls.get(l[i],l[j])+rs.get(r[i],r[j]);
    }
    void getrank(){int p=1;for(int i=0;i<n;++i)for(;p<=::n&&h[p]<=val[i];rank[p++]=i);rank[p]=n-1;}
}now;
struct query
{
    int ql,qr,vl,vr;i64 suf,ans;
    void merge(const data&x){ans=max(max(ans,x.ans),suf+x.pre),suf=max(suf+x.sum,x.suf);}
    void update()
    {
	if(qr<L||R<ql) return ;
	if(ql<=L&&R<=qr) merge(now.get(rank[vl],rank[vr]));
	else for(int i=max(ql,L);i<=std::min(qr,R);++i) if(vl<=r[i]&&r[i]<vr) ans=max(ans,suf+=a[i]),suf=max(suf,0ll);
    }
}q[N];
node build(int l,int r)
{
    node ans(r-l+1);int mid=(l+r)/2;
    if(l==r) return ans.init(a[l]),ans;
    node ls=build(l,mid),rs=build(mid+1,r);
    return ans.merge(ls,rs),ans;
}
void solve()
{
    it1=it2=0,now=build(L,R),now.getrank();
    for(int i=1;i<=m;++i) q[i].update();
}
int main()
{
    fread(ibuf,1,1<<23,stdin),n=read(),m=read();
    for(int i=1;i<=n;++i) h[i]=a[i]=read();
    std::sort(h+1,h+n+1);
    for(int i=1;i<=n;++i) r[i]=std::lower_bound(h+1,h+n+1,a[i])-h;
    for(int i=1;i<=m;++i) q[i].ql=read(),q[i].qr=read(),q[i].vl=std::lower_bound(h+1,h+n+1,read())-h,q[i].vr=std::upper_bound(h+1,h+n+1,read())-h;
    for(L=1;L<=n;L+=256) R=std::min(L+255,n),solve();
    for(int i=1;i<=m;++i) printf("%lld
",q[i].ans);
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12832962.html