bzoj4262 Sum

来源:互联网 发布:js隐藏input标签 编辑:程序博客网 时间:2024/06/12 20:25

题目大意

给出一个随机数列 {An},再给出 t 组询问,每次询问左端点在 [l1,r1] 范围内,右端点在 [l2,r2] 范围内的所有区间的区间最大值和区间最小值之差的和。

数据范围

1t40000,1l1r1100000,1l2r2100000.

解题报告

考虑离线的做法,把询问拆成 Q(r2,l1,r1)Q(l21,l1,r1)Q(i,l,r) 为右端点小于等于 i ,左端点在 [l,r] 范围内的区间的贡献。

从左往右移动右端点,当移动到位置 i 时,用单调栈找到最小的 j ,使得区间 [j,i] 的最大值为 Ai,则左端点在 [j,i] 范围内的区间最大值都会变为 Ai , 最小值的情况与此类似。

在线段树上打标记来维护,线段上每个节点记录:
v :(左端点在该节点范围内的)区间最新版本的最大值之和
s :区间历史版本(不包括最新版本)的 v 乘上对应的有效时间的乘积的和
t :最新版本更新的时间戳
再维护以下标记:
a :最新版本的要修改成的值
s :历史版本(不包括最新版本)的 a 乘上对应的有效时间的乘积的和
tl :最早的历史版本的 a 的时间戳
tr :最新版本的 a 的时间戳

向上合并的做法很简单:
x.t=max(x.lch.t,x.rch.t)
x.s=x.lch.s+x.lch.v(x.tx.lch.t)+x.rch.s+x.rch.v(x.tx.rch.t)
x.v=x.lch.v+x.rch.v

因为修改操作其实也和下放标记的操作类似,我们只用考虑如何用一个标记去修改一个节点维护的数据和标记:

用标记 (a,s,tl,tr) 修改节点 x 维护的数据:
x.s=x.s+x.v(tlx.t)+slen(x)
x.v=alen(x)
x.t=tr

用标记 (a,s,tl,tr) 修改标记 x :
如果标记 x 为空,直接将 (a,s,tl,tr) 赋值给 x
否则:
x.s=x.s+a(tla.tl)+s
x.a=a
x.tr=tr

之后就是简单的线段树操作了,不再赘述。

#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;int gint(){    char c; int f=1;    while(c=getchar(),c<48||c>57)        if(c=='-')f=-1;    int x=0;    for(;c>47&&c<58;c=getchar()){        x=x*10+c-48;    }    return x*f;}#define max_N 100005#define mod 1000000000int n,A[max_N];void init(){    int g1=1,g2=1;    for(int i=1;i<=n;++i){        g1=1ll*g1*1023%mod;        g2=1ll*g2*1025%mod;        A[i]=g1^g2;    }}struct QY{    int l,r,f,id,next;    QY(int l=0,int r=0,int f=0,int id=0,int n=0):l(l),r(r),f(f),id(id),next(n){}}Q[max_N];int t,head[max_N],tot;inline void add_QY(int x,int l,int r,int f,int id){    if(!x)return;    Q[++tot]=QY(l,r,f,id,head[x]),head[x]=tot;}typedef long long ll;struct data{    ll v,s;    int t;  }T[max_N<<2];inline data merge(const data&a,const data&b){    data res;    res.v=a.v+b.v;    res.t=max(a.t,b.t);    res.s=a.s+b.s+a.v*(res.t-a.t)+b.v*(res.t-b.t);    return res;}struct tags{    int a,tl,tr;    ll s;}tag[max_N<<2];inline void modify(data&x,const tags&y,int len){    x.s+=x.v*(y.tl-x.t)+y.s*len;    x.v=1ll*y.a*len;    x.t=y.tr;}inline void modify(tags&x,const tags&y){    if(x.a==-1){x=y; return;}    x.s+=1ll*x.a*(y.tl-x.tr)+y.s;    x.a=y.a,x.tr=y.tr;}inline void putdown(int x,int l,int m,int r){    if(tag[x].a==-1)return;    modify(T[x<<1],tag[x],m-l+1);    modify(tag[x<<1],tag[x]);    modify(T[x<<1|1],tag[x],r-m);    modify(tag[x<<1|1],tag[x]);    tag[x].a=-1;}#define lch x<<1,l,m#define rch x<<1|1,m+1,rvoid modify(int x,int l,int r,int ll,int rr,int a,int t){    if(ll<=l&&r<=rr){        tags y;        y.a=a,y.s=0,y.tl=y.tr=t;        modify(T[x],y,r-l+1);        modify(tag[x],y);        return;    }    int m=(l+r)>>1;    putdown(x,l,m,r);    if(ll<=m)modify(lch,ll,rr,a,t);    if(rr>m) modify(rch,ll,rr,a,t);    T[x]=merge(T[x<<1],T[x<<1|1]);}data query(int x,int l,int r,int ll,int rr){    if(l==ll&&r==rr)return T[x];    int m=(l+r)>>1;    putdown(x,l,m,r);    if(rr<=m)return query(lch,ll,rr);    if(ll>m) return query(rch,ll,rr);    return merge(query(lch,ll,m),query(rch,m+1,rr));}int st[max_N],top;ll ans[max_N];void Tree_init(int x,int l,int r){    T[x].v=T[x].s=T[x].t=0;    tag[x].a=-1;    if(l==r)return;    int m=(l+r)>>1;    Tree_init(x<<1,l,m);    Tree_init(x<<1|1,m+1,r);}int main(){//  freopen("input.txt","r",stdin);    t=gint();    for(int i=1,l1,r1,l2,r2;i<=t;++i){        l1=gint(),r1=gint(),l2=gint(),r2=gint();        add_QY(l2-1,l1,r1,-1,i),add_QY(r2,l1,r1,1,i);        n=max(n,max(r1,r2));    }    init();    Tree_init(1,1,n);    top=0;    for(int i=1;i<=n;++i){        while(top&&A[st[top]]<=A[i])--top;        modify(1,1,n,st[top]+1,i,A[i],i);        st[++top]=i;        for(int j=head[i];j;j=Q[j].next){            data tmp=query(1,1,n,Q[j].l,Q[j].r);            ans[Q[j].id]+=(tmp.s+tmp.v*(i-tmp.t+1))*Q[j].f;        }    }    Tree_init(1,1,n);    top=0;    for(int i=1;i<=n;++i){        while(top&&A[st[top]]>=A[i])--top;        modify(1,1,n,st[top]+1,i,A[i],i);        st[++top]=i;        for(int j=head[i];j;j=Q[j].next){            data tmp=query(1,1,n,Q[j].l,Q[j].r);            ans[Q[j].id]+=(tmp.s+tmp.v*(i-tmp.t+1))*Q[j].f*-1;        }    }    for(int i=1;i<=t;++i){        printf("%lld\n",ans[i]);    }    return 0;}
0 0