1. 程式人生 > >bzoj 4695 最假女選手 - segment tree beats

bzoj 4695 最假女選手 - segment tree beats

題解:
維護區間最大值mx、最大值出現次數mxcnt、嚴格次大值semx、最小值mn、最小值出現次數mncnt、嚴格次小值semn、區間和s、區間加法標記pt、區間最大值相對於其餘數字的加法標記mxpt、區間最小值相對於其餘數字的加法標記mnpt,一些細節形如:進行樸加法的時候mxpt和mnpt不變;先下傳區間加法標記;下傳兩個最值的標記的時候需要傳到最值來源的子樹;更新區間最值時,如果發現需要遞迴左右子樹並push_up來得到答案,需要先push_down;注意特判區間最大值等於區間最小值(即所有數字都相等,可以認為是做了一次樸素的加法);注意最大值等於嚴格次小值或者最小值等於嚴格次大值(其實本質上都是在說區間只有兩類數字的情況,此時以取min為例,若只對區間最大值有影響,而區間最大值等於區間嚴格次小值,那麼在原來的基礎上直接對嚴格次小值進行修改即可)。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define gc getchar()
#define N 500010
#define INF (INT_MAX-600000000)
#define inf (INT_MIN+600000000)
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit; inline int inn() { int x=0,s=1,ch;while(((ch=gc)<'0'||ch>'9')&&ch!='-'); if(ch^'-') x=ch^'0';else s=-1; while((ch=gc)>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return s*x; } int a[N]; inline int sgn(int x,int y) { return
(x<y)?-1:(x>y); } struct segment{ int mn,mx,mnpt,mxpt,pt,l,r,semn,semx,mxcnt,mncnt;lint s;segment *ch[2]; }*rt; inline int push_up(segment* &rt) { segment *&l=rt->ch[0],*&r=rt->ch[1]; rt->mnpt=rt->mxpt=rt->pt=0; rt->s=l->s+r->s;int d; d=sgn(l->mn,r->mn); if(d<0) rt->mn=l->mn,rt->mncnt=l->mncnt,rt->semn=min(l->semn,r->mn); if(d>0) rt->mn=r->mn,rt->mncnt=r->mncnt,rt->semn=min(r->semn,l->mn); if(d==0) rt->mn=l->mn,rt->mncnt=l->mncnt+r->mncnt,rt->semn=min(l->semn,r->semn); d=sgn(l->mx,r->mx); if(d>0) rt->mx=l->mx,rt->mxcnt=l->mxcnt,rt->semx=max(l->semx,r->mx); if(d<0) rt->mx=r->mx,rt->mxcnt=r->mxcnt,rt->semx=max(r->semx,l->mx); if(d==0) rt->mx=l->mx,rt->mxcnt=l->mxcnt+r->mxcnt,rt->semx=max(l->semx,r->semx); return 0; } int build(segment* &rt,int l,int r) { rt=new segment,rt->l=l,rt->r=r,rt->pt=rt->mnpt=rt->mxpt=0;int mid=(l+r)>>1; if(l==r) return rt->s=rt->mn=rt->mx=a[l],rt->mxcnt=rt->mncnt=1,rt->semn=INF,rt->semx=inf; return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r),push_up(rt); } int update(segment* &rt,int s,int t,int v,int tp); int push_down(segment* &rt); inline int update_tags(segment* &rt,int x) { return rt->pt+=x,rt->mn+=x,rt->mx+=x,rt->semn+=x,rt->semx+=x,rt->s+=(rt->r-rt->l+1ll)*x,0; } inline int update_min(segment* &rt,int x) { if(x<=rt->mn) return 0; if(x>=rt->semn) return push_down(rt),update(rt->ch[0],rt->l,rt->r,x,2),update(rt->ch[1],rt->l,rt->r,x,2),push_up(rt); int dlt=x-rt->mn;if(rt->mn==rt->mx) return update_tags(rt,dlt); if(rt->semx==rt->mn) rt->semx+=dlt; return rt->mnpt+=dlt,rt->mn+=dlt,rt->s+=(lint)dlt*rt->mncnt,0; } inline int update_max(segment* &rt,int x) { if(x>=rt->mx) return 0; if(x<=rt->semx) return push_down(rt),update(rt->ch[0],rt->l,rt->r,x,3),update(rt->ch[1],rt->l,rt->r,x,3),push_up(rt); int dlt=rt->mx-x;if(rt->mn==rt->mx) return update_tags(rt,-dlt); if(rt->semn==rt->mx) rt->semn-=dlt; return rt->mxpt-=dlt,rt->mx-=dlt,rt->s-=(lint)dlt*rt->mxcnt,0; } inline int push_down(segment* &rt) { if(rt->pt) update_tags(rt->ch[0],rt->pt),update_tags(rt->ch[1],rt->pt),rt->pt=0; if(rt->mnpt) { int d=sgn(rt->ch[0]->mn,rt->ch[1]->mn); if(d<=0) update_min(rt->ch[0],rt->ch[0]->mn+rt->mnpt); if(d>=0) update_min(rt->ch[1],rt->ch[1]->mn+rt->mnpt); rt->mnpt=0; } if(rt->mxpt) { int d=sgn(rt->ch[0]->mx,rt->ch[1]->mx); if(d>=0) update_max(rt->ch[0],rt->ch[0]->mx+rt->mxpt); if(d<=0) update_max(rt->ch[1],rt->ch[1]->mx+rt->mxpt); rt->mxpt=0; } return 0; } int update(segment* &rt,int s,int t,int x,int tp)//tp=1,plus; tp=2,x=max(x,v); tp=3,x=min(x,v) { int l=rt->l,r=rt->r,mid=(l+r)>>1; if(tp==2&&rt->mn>=x) return 0; if(tp==3&&rt->mx<=x) return 0; if(s<=l&&r<=t) { if(tp==1) update_tags(rt,x); if(tp==2) update_min(rt,x); if(tp==3) update_max(rt,x); return 0; } push_down(rt); if(s<=mid) update(rt->ch[0],s,t,x,tp); if(mid<t) update(rt->ch[1],s,t,x,tp); return push_up(rt); } lint query(segment* &rt,int s,int t,int tp)//tp=1,sum; tp=2,max; tp=3,min; { int l=rt->l,r=rt->r,mid=(l+r)>>1; if(s<=l&&r<=t) { if(tp==1) return rt->s; if(tp==2) return rt->mx; if(tp==3) return rt->mn; } push_down(rt);lint ans=0; if(tp==2) ans=inf; if(tp==3) ans=INF; if(s<=mid) { lint v=query(rt->ch[0],s,t,tp); if(tp==1) ans+=v; if(tp==2) ans=max(ans,v); if(tp==3) ans=min(ans,v); } if(mid<t) { lint v=query(rt->ch[1],s,t,tp); if(tp==1) ans+=v; if(tp==2) ans=max(ans,v); if(tp==3) ans=min(ans,v); } return ans; } int main() { int n=inn(); for(int i=1;i<=n;i++) a[i]=inn(); build(rt,1,n); for(int q=inn();q;q--) { int tp=inn(),l=inn(),r=inn(); if(tp<=3) update(rt,l,r,inn(),tp); else printf("%lld\n",query(rt,l,r,tp-3)); } return 0; }