BZOJ 4695: 最假女选手 segment-tree-beats
新学 segment-tree-beats.
这道题在区间取 min/max 的基础上还有一个区间加,那么显然要先做区间加,再取 min/max.
code:
// bzoj 最假女选手 #include <cstdio> #include <algorithm> #include <cstring> #define N 500007 #define ll long long #define lson x<<1 #define rson x<<1|1 using namespace std; char buf[100000],*p1,*p2; #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++) int rd() { int x=0,f=1; char s=nc(); while(s<'0'||s>'9') {if(s=='-')f=-1;s=nc();} while(s>='0'&&s<='9') x=(((x<<2)+x)<<1)+s-'0',s=nc(); return x*f; } const int inf=1<<30; int n; ll sum[N<<2]; int sn[N<<2],sm[N<<2],mn[N<<2],mx[N<<2],mi[N<<2],ma[N<<2],add[N<<2],len[N<<2]; void pushup(int x) { sum[x]=sum[lson]+sum[rson]; if(mn[lson]<mn[rson]) mn[x]=mn[lson],mi[x]=mi[lson],sn[x]=min(sn[lson],mn[rson]); if(mn[rson]<mn[lson]) mn[x]=mn[rson],mi[x]=mi[rson],sn[x]=min(sn[rson],mn[lson]); if(mn[lson]==mn[rson]) mn[x]=mn[lson],mi[x]=mi[lson]+mi[rson],sn[x]=min(sn[lson],sn[rson]); if(mx[lson]>mx[rson]) mx[x]=mx[lson],ma[x]=ma[lson],sm[x]=max(sm[lson],mx[rson]); if(mx[rson]>mx[lson]) mx[x]=mx[rson],ma[x]=ma[rson],sm[x]=max(sm[rson],mx[lson]); if(mx[lson]==mx[rson]) mx[x]=mx[lson],ma[x]=ma[lson]+ma[rson],sm[x]=max(sm[lson],sm[rson]); } void mark_add(int x,int v) { mn[x]+=v,mx[x]+=v,sn[x]+=v,sm[x]+=v,add[x]+=v; sum[x]+=(ll)len[x]*v; } void mark_max(int x,int v) { if(mx[x]>v) { sum[x]-=(ll)ma[x]*(mx[x]-v); if(mn[x]==mx[x]) mn[x]=v; if(sn[x]==mx[x]) sn[x]=v; mx[x]=v; } } void mark_min(int x,int v) { if(mn[x]<v) { sum[x]+=(ll)mi[x]*(v-mn[x]); if(sm[x]==mn[x]) sm[x]=v; if(mx[x]==mn[x]) mx[x]=v; mn[x]=v; } } void pushdown(int x) { if(add[x]) { mark_add(lson,add[x]); mark_add(rson,add[x]); add[x]=0; } mark_max(lson,mx[x]),mark_max(rson,mx[x]); mark_min(lson,mn[x]),mark_min(rson,mn[x]); } void build(int l,int r,int x) { len[x]=r-l+1; if(l==r) { sum[x]=(ll)rd(); mn[x]=mx[x]=sum[x],ma[x]=mi[x]=1; sn[x]=inf,sm[x]=-inf; return; } int mid=(l+r)>>1; build(l,mid,lson); build(mid+1,r,rson); pushup(x); } void addv(int l,int r,int x,int L,int R,int v) { if(l>=L&&r<=R) { mark_add(x,v); return; } pushdown(x); int mid=(l+r)>>1; if(L<=mid) addv(l,mid,lson,L,R,v); if(R>mid) addv(mid+1,r,rson,L,R,v); pushup(x); } void op_min(int l,int r,int x,int L,int R,int v) { if(v>=mx[x]) return; if(l>=L&&r<=R&&v>sm[x]) { mark_max(x,v); return; } pushdown(x); int mid=(l+r)>>1; if(L<=mid) op_min(l,mid,lson,L,R,v); if(R>mid) op_min(mid+1,r,rson,L,R,v); pushup(x); } void op_max(int l,int r,int x,int L,int R,int v) { if(v<=mn[x]) return; if(l>=L&&r<=R&&v<sn[x]) { mark_min(x,v); return; } pushdown(x); int mid=(l+r)>>1; if(L<=mid) op_max(l,mid,lson,L,R,v); if(R>mid) op_max(mid+1,r,rson,L,R,v); pushup(x); } void query(int l,int r,int x,int L,int R,int &MIN,int &MAX,ll &SUM) { if(l>=L&&r<=R) { MIN=min(MIN,mn[x]); MAX=max(MAX,mx[x]); SUM+=sum[x]; return; } pushdown(x); int mid=(l+r)>>1; if(L<=mid) query(l,mid,lson,L,R,MIN,MAX,SUM); if(R>mid) query(mid+1,r,rson,L,R,MIN,MAX,SUM); pushup(x); } int main() { // freopen("input.in","r",stdin); n=rd(),build(1,n,1); int m=rd(); for(int i=1;i<=m;++i) { int op=rd(),l=rd(),r=rd(),x; if(op==1) x=rd(),addv(1,n,1,l,r,x); if(op==2) x=rd(),op_max(1,n,1,l,r,x); if(op==3) x=rd(),op_min(1,n,1,l,r,x); if(op>=4) { ll SUM=0; int MIN=inf,MAX=-inf; query(1,n,1,l,r,MIN,MAX,SUM); if(op==4) printf("%lld\n",SUM); if(op==5) printf("%d\n",MAX); if(op==6) printf("%d\n",MIN); } } return 0; }