BZOJ4695 最假女选手

传送门

题目大意

维护一个序列,支持区间加,区间取$max,min$,区间求和,区间求最大最小值。

 

题解

区间取$max,min$必然要用到神奇的吉老师线段树,即维护区间最大值、最大值数量,次大值来剪枝。

即,当取$min$介于最大值和次大值之间时进行修改,否则暴力递归子树。

区间取$max$同理。

这道题还要套上区间加和区间求和,所以$pushdown$的时候还是比较麻烦的,注意要特殊处理最大值等于最小值或最大值等于严格次小值的情况。

复杂度据说是$O(N\log^2N)$吧,反正我不会证

然而实际上跑的很快,虽然我的代码T掉了嘤嘤嘤

 

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define mid ((l+r)>>1)
#define M 800010
#define INF 2000000000
using namespace std;
int read(){
	int nm=0,fh=1; int cw=getchar();
	for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
	for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
	return nm*fh;
}
void write(LL x){if(x<0) putchar('-'),x=-x;if(x>9) write(x/10);putchar((int)(x%10+'0'));}
LL p[M<<1],ans;
int tg[M<<1],mx[M<<1],mn[M<<1],sx[M<<1],sn[M<<1],A[M],cx[M<<1],cn[M<<1];
int n,m,T,L[M<<1],R[M<<1],cnt,u[M],v[M],dt[M],t[M],Rt;
inline void pushup(int x){
	int ls=L[x],rs=R[x]; p[x]=p[ls]+p[rs];
	if(mx[ls]>mx[rs]) mx[x]=mx[ls],cx[x]=cx[ls],sx[x]=max(mx[rs],sx[ls]);
	if(mx[ls]<mx[rs]) mx[x]=mx[rs],cx[x]=cx[rs],sx[x]=max(mx[ls],sx[rs]);
	if(mx[ls]==mx[rs]) mx[x]=mx[ls],cx[x]=cx[ls]+cx[rs],sx[x]=max(sx[ls],sx[rs]);
	if(mn[ls]<mn[rs]) mn[x]=mn[ls],cn[x]=cn[ls],sn[x]=min(mn[rs],sn[ls]);
	if(mn[ls]>mn[rs]) mn[x]=mn[rs],cn[x]=cn[rs],sn[x]=min(mn[ls],sn[rs]);
	if(mn[ls]==mn[rs]) mn[x]=mn[ls],cn[x]=cn[ls]+cn[rs],sn[x]=min(sn[ls],sn[rs]);
}
inline void inc(int x,LL len,int dt){tg[x]+=dt,mx[x]+=dt,mn[x]+=dt,sx[x]+=dt,sn[x]+=dt,p[x]+=len*((LL)dt);}
inline void upmin(int num,int y){
	if(mx[y]==mn[y]) mn[y]=num; if(mx[y]==sn[y]) sn[y]=num;
	p[y]+=(LL)(num-mx[y])*((LL)cx[y]),mx[y]=num;
}
inline void upmax(int num,int y){
	if(mx[y]==mn[y]) mx[y]=num; if(mn[y]==sx[y]) sx[y]=num;
	p[y]+=(LL)(num-mn[y])*((LL)cn[y]),mn[y]=num;
}
inline void pushdown(int x,int l,int r){
	int ls=L[x],rs=R[x]; LL lm=(mid-l+1),rm=(r-mid);
	if(tg[x]) inc(ls,lm,tg[x]),inc(rs,rm,tg[x]),tg[x]=0;
	if(mx[x]<mx[ls]) upmin(mx[x],ls); if(mx[x]<mx[rs]) upmin(mx[x],rs);
	if(mn[x]>mn[ls]) upmax(mn[x],ls); if(mn[x]>mn[rs]) upmax(mn[x],rs);
}
void build(int &x,int l,int r){
	x=++cnt;
	if(l==r){p[x]=mx[x]=mn[x]=A[l],cx[x]=cn[x]=1;sx[x]=-INF,sn[x]=INF;return;}
	build(L[x],l,mid),build(R[x],mid+1,r),pushup(x);
}
LL qry(int x,int l,int r,int ls,int rs,int typ){
	if(rs<l||r<ls){return typ==4?0:(typ==5?-INF:INF);}
	if(ls<=l&&r<=rs){return typ==4?p[x]:(typ==5?mx[x]:mn[x]);}
	pushdown(x,l,r); LL t1=qry(L[x],l,mid,ls,rs,typ);
	LL t2=qry(R[x],mid+1,r,ls,rs,typ); pushup(x);
	return typ==4?t1+t2:(typ==5?max(t1,t2):min(t1,t2));
}
void add(int x,int l,int r,int ls,int rs,int dx){
	if(r<ls||rs<l) return;
	if(ls<=l&&r<=rs){inc(x,r-l+1,dx);return;}
	pushdown(x,l,r),add(L[x],l,mid,ls,rs,dx);
	add(R[x],mid+1,r,ls,rs,dx),pushup(x);
}
void mdf(int x,int l,int r,int ls,int rs,int typ,int dx){
	if(r<ls||rs<l||(typ==2&&mn[x]>=dx)||(typ==3&&mx[x]<=dx)) return;
	if(ls<=l&&r<=rs&&((typ==2&&sn[x]>dx)||(typ==3&&sx[x]<dx))){
		if(typ==2) upmax(dx,x);else upmin(dx,x); return;
	}
	pushdown(x,l,r),mdf(L[x],l,mid,ls,rs,typ,dx);
	mdf(R[x],mid+1,r,ls,rs,typ,dx),pushup(x);
}
int main(){
	n=read();
	for(int i=1;i<=n;i++) A[i]=read(); build(Rt,1,n);
	for(int T=read(),tpe,ls,rs,dx;T;--T){
		tpe=read(),ls=read(),rs=read();
		if(tpe>3) ans=qry(Rt,1,n,ls,rs,tpe),write(ans),putchar('\n');
		else if(tpe>1) dx=read(),mdf(Rt,1,n,ls,rs,tpe,dx);
		else dx=read(),add(Rt,1,n,ls,rs,dx);
	}
	return 0;
}

 

posted @ 2018-10-08 19:15  OYJason  阅读(305)  评论(0编辑  收藏  举报