[FROM BZOJ]最假女選手

傳送門

SOL
這不是普通的線段樹,要使用線段樹Beats(又稱吉司機線段樹
其他操作都好說,主要來講一講2、3操作,也就是Beats的不同之處
2、3其實是一樣的,這裏以 操作2 爲例講一講具體實現
操作2:把一個區間[L,R] 裏小於x 的數變成x
如果暴力修改葉子節點,複雜度就是O(N2logN)O(N^2logN)的,肯定炸了,Beats的優點在於它額外維護了幾個值——除了區間最小值mn,還有次小值sn,最小值的出現次數cn
每次遞歸到要修改的區間,判斷x與mn的關係,如果x<=mnx<=mn,那麼就不用向下修改,如果mn<x<snmn<x<sn就對mn,sum修改
操作3同理
lazy標記?不需要額外維護了,可以直接用最大值mx,最小值mn下傳即可,這樣就不用遞歸修改整個區間
據說複雜度是O(Nlog2N)O(Nlog^2N)的,但我不會證,wtcl

代碼:

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define LL long long
template<typename T>inline T nin(cs T&a,cs T&b){return a<b?a:b;}
template<typename T>inline T nax(cs T&a,cs T&b){return a>b?a:b;}
inline char nc(){
    static char buf[10000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,10000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd(){
	int re data=0,w=1;char ch=nc();
	while(!isdigit(ch)&&ch!='-')ch=nc();
	if(ch=='-')w=-1,ch=nc();
	while(isdigit(ch))data=(data<<1)+(data<<3)+(ch^48),ch=nc();
	return data*w;
}
#define lc (p<<1)
#define rc (p<<1|1)
cs int N=5e5+5;
int n,m,tp,L,R,x,a[N];
struct seg{int l,r,mx,sx,cx,mn,sn,cn,len,tag;LL sum;}t[N<<2];
inline void pushnow(cs int&p,int v){
	t[p].mx+=v,t[p].mn+=v,t[p].tag+=v,t[p].sum+=(LL)t[p].len*v;
	if(t[p].sx!=INT_MIN)t[p].sx+=v;if(t[p].sn!=INT_MAX)t[p].sn+=v;
}
inline void pushup(cs int&p){
	t[p].sum=t[lc].sum+t[rc].sum,
	t[p].mx=nax(t[lc].mx,t[rc].mx),t[p].cx=(t[lc].mx^t[p].mx?0:t[lc].cx)+(t[rc].mx^t[p].mx?0:t[rc].cx),
	t[p].mn=nin(t[lc].mn,t[rc].mn),t[p].cn=(t[lc].mn^t[p].mn?0:t[lc].cn)+(t[rc].mn^t[p].mn?0:t[rc].cn),
	t[p].sx=nax(nax(t[lc].sx,t[rc].sx),(t[lc].mx^t[rc].mx)?nin(t[lc].mx,t[rc].mx):INT_MIN),
	t[p].sn=nin(nin(t[lc].sn,t[rc].sn),(t[lc].mn^t[rc].mn)?nax(t[lc].mn,t[rc].mn):INT_MAX);
}
inline void drop(cs int&p,cs int&v){
	t[p].sum+=(LL)t[p].cx*(v-t[p].mx),t[p].mx=v,t[p].mn=nin(t[p].mn,v);
	if(t[p].mx==t[p].mn)t[p].sum=(LL)t[p].len*v,t[p].cx=t[p].cn=t[p].len,t[p].sx=INT_MIN,t[p].sn=INT_MAX;
	else t[p].sn=nin(t[p].sn,v);
}
inline void rise(cs int&p,cs int&v){
	t[p].sum+=(LL)t[p].cn*(v-t[p].mn),t[p].mn=v,t[p].mx=nax(t[p].mx,v);
	if(t[p].mx==t[p].mn)t[p].sum=(LL)t[p].len*v,t[p].cx=t[p].cn=t[p].len,t[p].sx=INT_MIN,t[p].sn=INT_MAX;
	else t[p].sx=nax(t[p].sx,v);
}
inline void pushdown(cs int&p){
	if(t[p].tag)pushnow(lc,t[p].tag),pushnow(rc,t[p].tag),t[p].tag=0;
	if(t[lc].mx>t[p].mx&&t[lc].sx<t[p].mx)drop(lc,t[p].mx);
	if(t[rc].mx>t[p].mx&&t[rc].sx<t[p].mx)drop(rc,t[p].mx);
	if(t[lc].mn<t[p].mn&&t[lc].sn>t[p].mn)rise(lc,t[p].mn);
	if(t[rc].mn<t[p].mn&&t[rc].sn>t[p].mn)rise(rc,t[p].mn);
}
inline void build(int p,int l,int r){
	t[p].len=r-l+1,t[p].l=l,t[p].r=r;
	if(l==r){t[p].sum=t[p].mn=t[p].mx=a[l],t[p].sx=INT_MIN,t[p].sn=INT_MAX,t[p].cx=t[p].cn=1;return;}
	int re mid=l+r>>1;
	build(lc,l,mid),build(rc,mid+1,r),pushup(p);
}
inline void add(int p,cs int&ql,cs int&qr,cs int&v){
	if(!v)return;
	if(ql<=t[p].l&&t[p].r<=qr){pushnow(p,v);return;}
	int re mid=t[p].l+t[p].r>>1;
	pushdown(p);
	if(ql<=mid)add(lc,ql,qr,v);
	if(qr>mid)add(rc,ql,qr,v);
	pushup(p);
}
inline void smaller(int p,cs int&ql,cs int&qr,cs int&v){
	if(t[p].mx<=v)return;
	if(ql<=t[p].l&&t[p].r<=qr&&t[p].sx<v){drop(p,v);return;}
	int re mid=t[p].l+t[p].r>>1;
	pushdown(p);
	if(ql<=mid)smaller(lc,ql,qr,v);
	if(qr>mid)smaller(rc,ql,qr,v);
	pushup(p);
}
inline void bigger(int p,cs int&ql,cs int&qr,cs int&v){
	if(t[p].mn>=v)return;
	if(ql<=t[p].l&&t[p].r<=qr&&t[p].sn>v){rise(p,v);return;}
	int re mid=t[p].l+t[p].r>>1;
	pushdown(p);
	if(ql<=mid)bigger(lc,ql,qr,v);
	if(qr>mid)bigger(rc,ql,qr,v);
	pushup(p);
}
inline LL qsum(int p,cs int&ql,cs int&qr){
	if(ql<=t[p].l&&t[p].r<=qr)return t[p].sum;
	int re mid=t[p].l+t[p].r>>1;LL re ans=0;
	pushdown(p);
	if(ql<=mid)ans+=qsum(lc,ql,qr);
	if(qr>mid)ans+=qsum(rc,ql,qr);
	return ans;
}
inline int qmax(int p,cs int&ql,cs int&qr){
	if(ql<=t[p].l&&t[p].r<=qr)return t[p].mx;
	int re mid=t[p].l+t[p].r>>1,ans=INT_MIN;
	pushdown(p);
	if(ql<=mid)ans=max(ans,qmax(lc,ql,qr));
	if(qr>mid)ans=max(ans,qmax(rc,ql,qr));
	return ans;
}
inline int qmin(int p,cs int&ql,cs int&qr){
	if(ql<=t[p].l&&t[p].r<=qr)return t[p].mn;
	int re mid=t[p].l+t[p].r>>1,ans=INT_MAX;
	pushdown(p);
	if(ql<=mid)ans=min(ans,qmin(lc,ql,qr));
	if(qr>mid)ans=min(ans,qmin(rc,ql,qr));
	return ans;
}
signed main(){
	n=rd();
	for(int re i=1;i<=n;++i)a[i]=rd();
	build(1,1,n),m=rd();
	while(m--){
		tp=rd(),L=rd(),R=rd();
		if(tp==1)add(1,L,R,x=rd());
		if(tp==2)bigger(1,L,R,x=rd());
		if(tp==3)smaller(1,L,R,x=rd());
		if(tp==4)printf("%lld\n",qsum(1,L,R));
		if(tp==5)printf("%d\n",qmax(1,L,R));
		if(tp==6)printf("%d\n",qmin(1,L,R));
	}return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章