BZOJ4262 : Sum

最大值和最小值的问题是独立且相似的,考虑最大值:

考虑离线,设ask(i,l,r)为以1到i为右端点时左端点在区间[l,r]内的区间最大值的和。

从1到n枚举右端点,假设现在是i,那么可以通过单调栈求出最小的j使得[j,i]内a[i]是最大值。

然后左端点在[j,i]区间内的所有区间最大值都应当变为a[i],且所有答案应该加上本身的值。

通过线段树打标记维护,时间复杂度$O(n\log n)$。

对于线段树上每个节点,维护以下信息:

v : 区间内所有数的和

s : 历史上所有v的和

l : 区间长度

a,b,c,d : 标记,分别表示生效之后

v'=a*v+b*l

s'=c*v+d*l+s

 

#include<cstdio>
#include<algorithm>
#define N 262150
typedef long long ll;
int n,m,i,j,l1,r1,l2,r2,a[N],q[N],t,cnt;ll t1,t2,ans[N];
struct Q{
  int i,l,r,p,t;
  Q(){}
  Q(int _i,int _l,int _r,int _p,int _t){i=_i,l=_l,r=_r,p=_p,t=_t;}
}b[N];
inline bool cmp(const Q&a,const Q&b){return a.i<b.i;}
struct tag{
  ll a,b,c,d;
  tag(){a=1,b=c=d=0;}
  tag(ll _a,ll _b,ll _c,ll _d){a=_a,b=_b,c=_c,d=_d;}
  inline bool ex(){return a!=1||b||c||d;}
  inline tag operator+(const tag&B){
    return tag(a*B.a,b*B.a+B.b,a*B.c+c,d+b*B.c+B.d);
  }
}tmp;
struct Node{ll v,s;int l;tag t;}T[N];
inline void add1(int x,tag p){
  T[x].s+=p.c*T[x].v+p.d*T[x].l;
  T[x].v=p.a*T[x].v+p.b*T[x].l;
  T[x].t=T[x].t+p;
}
inline void pb(int x){
  if(T[x].t.ex()){
    add1(x<<1,T[x].t);
    add1(x<<1|1,T[x].t);
    T[x].t=tag();
  }
}
inline void up(int x){
  T[x].v=T[x<<1].v+T[x<<1|1].v;
  T[x].s=T[x<<1].s+T[x<<1|1].s;
}
void build(int x,int a,int b){
  T[x].v=T[x].s=0,T[x].l=b-a+1,T[x].t=tag();
  if(a==b)return;
  int mid=(a+b)>>1;
  build(x<<1,a,mid),build(x<<1|1,mid+1,b);
}
void add(int x,int a,int b,int c,int d){
  if(c<=a&&b<=d){add1(x,tmp);return;}
  pb(x);
  int mid=(a+b)>>1;
  if(c<=mid)add(x<<1,a,mid,c,d);
  if(d>mid)add(x<<1|1,mid+1,b,c,d);
  up(x);
}
ll ask(int x,int a,int b,int c,int d){
  if(c<=a&&b<=d)return T[x].s;
  pb(x);
  int mid=(a+b)>>1;ll t=0;
  if(c<=mid)t=ask(x<<1,a,mid,c,d);
  if(d>mid)t+=ask(x<<1|1,mid+1,b,c,d);
  return up(x),t;
}
int main(){
  for(scanf("%d",&m);i<m;i++){
    scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
    if(l2>1)b[++cnt]=Q(l2-1,l1,r1,i,-1);
    b[++cnt]=Q(r2,l1,r1,i,1);
    if(n<r1)n=r1;
    if(n<r2)n=r2;
  }
  std::sort(b+1,b+cnt+1,cmp);
  for(t1=1023,t2=1025,i=1;i<=n;i++,t1=t1*1023%1000000000,t2=t2*1025%1000000000)a[i]=t1^t2;
  for(build(1,1,n),i=j=1;i<=n;q[++t]=i++){
    while(t&&a[q[t]]<a[i])t--;
    tmp=tag(0,a[i],0,0),add(1,1,n,q[t]+1,i),add1(1,tag(1,0,1,0));
    while(j<=cnt&&b[j].i==i)ans[b[j].p]+=ask(1,1,n,b[j].l,b[j].r)*b[j].t,j++;
  }
  for(build(1,1,n),t=0,i=j=1;i<=n;q[++t]=i++){
    while(t&&a[q[t]]>a[i])t--;
    tmp=tag(0,a[i],0,0),add(1,1,n,q[t]+1,i),add1(1,tag(1,0,1,0));
    while(j<=cnt&&b[j].i==i)ans[b[j].p]-=ask(1,1,n,b[j].l,b[j].r)*b[j].t,j++;
  }
  for(i=0;i<m;i++)printf("%lld\n",ans[i]);
  return 0;
}

  

posted @ 2015-09-20 23:59  Claris  阅读(1589)  评论(0编辑  收藏  举报