吉司機線段樹


學了一下吉老師的在某年WC的講的線段樹。

特來總結,學習一番.

PDF地址:吉老師的Segment tree Beats!

楔子:給出一個數列A 每次讓某個區間中的\(a_i\)對x取min 詢問某個區間的和。

\(n,m\leq 500000\)

由於存在多次詢問 我們進行標記永久化也沒什么用 如果是一次的話我可以每次把標記標記到區間 最后求值即可。

這里要引出吉司機線段樹了。

做法:線段樹維護區間最大值mx 最大值次數 T 次大值 se 維護區間和 sum

當某個區間要對x取min時 顯然 mx<=x直接跳過這個區間 se<x<mx時 直接修改打上標記然后退出。

最壞的情況 x<se 此時我們暴力遞歸子區間。

通過吉老師的證明 這復雜度最壞是mlog^2的!

具體證明:自己看pdf... 好吧聽說吉老師證明是萎的 具體證明看國家集訓隊論文 時間復雜度 每次修改時間復雜度為log^2

說了這么多了 上例題/cy

bzoj 4695最假女選手

雖然很復雜 但是 還是要碼的 要迎男而上 男上加男?

//#include<bits\stdc++.h>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 2000000000
#define ld long double
#define pb push_back
#define put(x) printf("%d\n",x)
#define rep(p,n,i) for(RE int i=p;i<=n;++i)
#define pii pair<ll,ll> 
#define F first
#define mk make_pair
#define mod 64123
#define RE register
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define l(p) t[p].l
#define r(p) t[p].r
#define sum(p) t[p].sum
#define mx(p) t[p].mx
#define mn(p) t[p].mn
#define sx(p) t[p].sx
#define sn(p) t[p].sn
#define tag(p) t[p].tag
#define cx(p) t[p].cx
#define cn(p) t[p].cn
#define zz p<<1
#define yy p<<1|1
#define ls p<<1,l,r
#define rs p<<1|1,l,r
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
	return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
	RE int x=0,f=1;char ch=getc();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
	return x*f;
}
const int MAXN=500010;
int n,Q;
struct wy
{
	int l,r,tag;
	ll sum;
	int mx,sx,cx;
	int mn,sn,cn;
}t[MAXN<<2];
inline void pushup(int p)
{
	sum(p)=sum(zz)+sum(yy);
	if(mx(zz)>mx(yy))mx(p)=mx(zz),cx(p)=cx(zz),sx(p)=max(mx(yy),sx(zz));
	if(mx(yy)>mx(zz))mx(p)=mx(yy),cx(p)=cx(yy),sx(p)=max(mx(zz),sx(yy));
	if(mx(zz)==mx(yy))mx(p)=mx(zz),cx(p)=cx(zz)+cx(yy),sx(p)=max(sx(zz),sx(yy));
	if(mn(zz)<mn(yy))mn(p)=mn(zz),cn(p)=cn(zz),sn(p)=min(mn(yy),sn(zz));
	if(mn(yy)<mn(zz))mn(p)=mn(yy),cn(p)=cn(yy),sn(p)=min(mn(zz),sn(yy));
	if(mn(zz)==mn(yy))mn(p)=mn(zz),cn(p)=cn(zz)+cn(yy),sn(p)=min(sn(zz),sn(yy));
}
inline void build(int p,int l,int r)
{
	l(p)=l;r(p)=r;
	if(l==r)
	{
		mn(p)=mx(p)=get(sum(p));
		cn(p)=cx(p)=1;
		sx(p)=-INF;sn(p)=INF;
		return;
	}
	int mid=(l+r)>>1;
	build(zz,l,mid);
	build(yy,mid+1,r);
	pushup(p);
}
inline void pushdown(int p)
{
	int mid=(l(p)+r(p))>>1;
	if(tag(p))
	{
		int x=tag(p);tag(p)=0;
		mx(zz)+=x;tag(zz)+=x;mn(zz)+=x;sx(zz)+=x;sn(zz)+=x;sum(zz)+=(ll)(mid-l(p)+1)*x;
		mx(yy)+=x;tag(yy)+=x;mn(yy)+=x;sx(yy)+=x;sn(yy)+=x;sum(yy)+=(ll)(r(p)-mid)*x;
	}
	if(mx(p)<mx(zz))
	{
		if(mn(zz)==mx(zz))mn(zz)=mx(p);
		if(sn(zz)==mx(zz))sn(zz)=mx(p);
		sum(zz)-=(ll)(mx(zz)-mx(p))*cx(zz);
		mx(zz)=mx(p);
	}
	if(mx(p)<mx(yy))
	{
		if(mn(yy)==mx(yy))mn(yy)=mx(p);
		if(sn(yy)==mx(yy))sn(yy)=mx(p);
		sum(yy)-=(ll)(mx(yy)-mx(p))*cx(yy);
		mx(yy)=mx(p);
	}
	if(mn(p)>mn(zz))
	{
		if(mx(zz)==mn(zz))mx(zz)=mn(p);
		if(sx(zz)==mn(zz))sx(zz)=mn(p);
		sum(zz)+=(ll)(mn(p)-mn(zz))*cn(zz);
		mn(zz)=mn(p);
	}
	if(mn(p)>mn(yy))
	{
		if(mx(yy)==mn(yy))mx(yy)=mn(p);
		if(sx(yy)==mn(yy))sx(yy)=mn(p);
		sum(yy)+=(ll)(mn(p)-mn(yy))*cn(yy);
		mn(yy)=mn(p);
	}
}
inline void change(int p,int l,int r,int x)
{
	if(l<=l(p)&&r>=r(p))
	{
		sum(p)+=(ll)(r(p)-l(p)+1)*x;
		mx(p)+=x;mn(p)+=x;
		sx(p)+=x;sn(p)+=x;
		tag(p)+=x;return;
	}
	int mid=(l(p)+r(p))>>1;
	pushdown(p);
	if(l<=mid)change(ls,x);
	if(r>mid)change(rs,x);
	pushup(p);
}
inline void modifymax(int p,int l,int r,int x)
{
	if(mn(p)>=x)return;
	if(l<=l(p)&&r>=r(p)&&sn(p)>x)
	{
		sum(p)+=(ll)(x-mn(p))*cn(p);
		if(sx(p)==mn(p))sx(p)=x;
		if(mx(p)==mn(p))mx(p)=x;
		mn(p)=x;return;
	}
	int mid=(l(p)+r(p))>>1;
	pushdown(p);
	if(l<=mid)modifymax(ls,x);
	if(r>mid)modifymax(rs,x);
	pushup(p);
}
inline void modifymin(int p,int l,int r,int x)
{
	if(mx(p)<=x)return;
	if(l<=l(p)&&r>=r(p)&&sx(p)<x)
	{
		sum(p)-=(ll)(mx(p)-x)*cx(p);
		if(sn(p)==mx(p))sn(p)=x;
		if(mn(p)==mx(p))mn(p)=x;
		mx(p)=x;return;
	}
	int mid=(l(p)+r(p))>>1;
	pushdown(p);
	if(l<=mid)modifymin(ls,x);
	if(r>mid)modifymin(rs,x);
	pushup(p);
}
inline ll ask(int p,int l,int r)
{
	if(l<=l(p)&&r>=r(p))return sum(p);
	int mid=(l(p)+r(p))>>1;
	pushdown(p);ll cnt=0;
	if(l<=mid)cnt+=ask(ls);
	if(r>mid)cnt+=ask(rs);
	return cnt;
}
inline int querymax(int p,int l,int r)
{
	if(l<=l(p)&&r>=r(p))return mx(p);
	int mid=(l(p)+r(p))>>1;
	pushdown(p);int cnt=-INF;
	if(l<=mid)cnt=max(cnt,querymax(ls));
	if(r>mid)cnt=max(cnt,querymax(rs));
	return cnt;
}
inline int querymin(int p,int l,int r)
{
	if(l<=l(p)&&r>=r(p))return mn(p);
	int mid=(l(p)+r(p))>>1;
	pushdown(p);int cnt=INF;
	if(l<=mid)cnt=min(cnt,querymin(ls));
	if(r>mid)cnt=min(cnt,querymin(rs));
	return cnt;
}
int main()
{
	freopen("1.in","r",stdin);
	get(n);build(1,1,n);
	get(Q);
	rep(1,Q,i)
	{
		int op,x,y;
		get(op);get(x);get(y);
		if(op==1)change(1,x,y,read());
		if(op==2)modifymax(1,x,y,read());
		if(op==3)modifymin(1,x,y,read());
		if(op==4)printf("%lld\n",ask(1,x,y));
		if(op==5)printf("%d\n",querymax(1,x,y));
		if(op==6)printf("%d\n",querymin(1,x,y));
	}
	return 0;
}

一遍AC 再見 這又臭又長的代碼 把我給寫蒙蔽了 沒想到這么長 盡管我已經極力壓行了。。

考慮標記問題 我們在下放標記是 有兩類標記 可以發現 賦值標記可以被區間加標記給修改 區間加標記則不能被賦值標記修改。

所以我們在進行區間修改時 我們把賦值標記修改后就相當於賦值標記后來 區間加標記先來這個順序。

所以再pushdown的時候也同樣 先區間賦值 再單點賦值。

需要注意的是 修改mx時會影響到mn sn,修改mn時可能會影響到mx sx.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM