zoukankan      html  css  js  c++  java
  • 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);
    }
    
  • 相关阅读:
    MySQL之存储过程和函数
    Mysql中的常用函数:
    Mysql之使用Mysql运算符
    Mysql之单表记录查询
    Mysql之触发器的操作:
    Mysql之视图的操作
    Mysql之表的操作与索引操作
    Mysql之基本操作与数据类型
    Java多线程之生产者消费者
    Java多线程
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12832962.html
Copyright © 2011-2022 走看看