【OI/ACM】模板合集

写这样一个模板合集的原因其实很简单,在打线上比赛时,每一份代码都亲力亲为将导致写代码的时间大幅增加,间接导致 rk++ ,同时这样一份板子库也便于笔者自己复习。

遂于 2026.7.25 起笔,以后也会不定时添加内容。

注:希望读者善用 ctrl + F 。

输入输出优化

快读 :

inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}

快写 :

inline void write(int x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10+'0');
	return ;
} 

高精度

收录了高精度下的 加法 ,减法 ,乘法 ,除法 ,取模。

struct bignum{
    char op;
    int len, num[N];
    bignum(){
        memset(num, 0, sizeof(num));
        len = 1; op = '+';
    }
    static inline int cmp(const bignum &x, const bignum &y) {
        if (x.op == '+' && y.op == '-') return 1;
        if (x.op == '-' && y.op == '+') return 3;
        if (x.op == '-' && y.op == '-') {
            if (x.len > y.len) return 3;
            if (x.len < y.len) return 1;
            for (int i = x.len; i >= 1; i--) {
                if (x.num[i] > y.num[i]) return 3;
                if (x.num[i] < y.num[i]) return 1;
            }
            return 2;
        }
        // x.op == '+' && y.op == '+'
        if (x.len > y.len) return 1;
        if (x.len < y.len) return 3;
        for (int i = x.len; i >= 1; i--) {
            if (x.num[i] > y.num[i]) return 1;
            if (x.num[i] < y.num[i]) return 3;
        }
        return 2;
    }
    friend bool operator > (const bignum &x,const bignum &y){
        return bignum::cmp(x,y) == 1;
    }
    friend bool operator < (const bignum &x,const bignum &y){
        return bignum::cmp(x,y) == 3;
    }
    friend bool operator == (const bignum &x,const bignum &y){
        return bignum::cmp(x,y) == 2;
    }
    friend bool operator <= (const bignum &x,const bignum &y){
        return bignum::cmp(x,y) >= 2;
    }
    friend bool operator >= (const bignum &x,const bignum &y){
        return bignum::cmp(x,y) <= 2;
    }
    friend bool operator != (const bignum &x,const bignum &y){
        return bignum::cmp(x,y) != 2;
    }
    static inline void Swap(bignum &x,bignum &y){
        bignum tmp = x;
        x = y; y = tmp;
    }
    friend bignum operator + (const bignum &x,const bignum &y){
        bignum res;
        if(x.op == '-' && y.op == '+') return y - x;
        if(x.op == '+' && y.op == '-') return x - y;
        res.op = (x.op == '-' && y.op == '-') ? '-' : '+';
        res.len = max(x.len, y.len);
        for(int i = 1; i <= res.len; i++)
            res.num[i] = x.num[i] + y.num[i];
        for(int i = 1; i <= res.len; i++){
            if(res.num[i] < 10) continue;
            res.num[i+1] += res.num[i] / 10;
            res.num[i] %= 10;
            res.len = max(res.len, i+1);
        }
        return res;
    }
    friend bignum operator - (const bignum &a,const bignum &b){
        bignum res, x = a, y = b;
        res.len = max(x.len, y.len);
        if(x < y) {
            bignum::Swap(x, y);
            res.op = '-';
        }
        for(int i = 1; i <= res.len; i++)
            res.num[i] = x.num[i] - y.num[i];
        for(int i = 1; i <= res.len; i++){
            if(res.num[i] >= 0) continue;
            res.num[i] += 10;
            res.num[i+1]--;
        }
        while(res.len > 1 && res.num[res.len] == 0) res.len--;
        if(res.len == 1 && res.num[1] == 0) res.op = '+';
        return res;
    }
    friend bignum operator * (const bignum &x,const bignum &y){
        bignum res;
        if(x.op != y.op) res.op = '-';
        res.len = x.len + y.len;
        for(int i = 1; i <= x.len; i++)
            for(int j = 1; j <= y.len; j++)
                res.num[i+j-1] += x.num[i] * y.num[j];
        for(int i = 1; i <= res.len; i++){
            if(res.num[i] < 10) continue;
            res.num[i+1] += res.num[i] / 10;
            res.num[i] %= 10;
            res.len = max(res.len, i+1);
        }
        while(res.len > 1 && res.num[res.len] == 0) res.len--;
        if(res.len == 1 && res.num[1] == 0) res.op = '+';
        return res;
    }
    static inline bignum numcopy(const bignum &x, int pos){
        bignum ret;
        for(int i = 1; i <= x.len; i++) ret.num[i+pos-1] = x.num[i];
        ret.len = x.len + pos - 1;
        ret.op = '+';
        return ret;
    }
    friend bignum operator / (const bignum &a,const bignum &y){
        bignum res, x = a;
        if(x < y) return bignum();
        if(x.op != y.op) res.op = '-';
        res.len = x.len - y.len + 1;
        for(int i = res.len; i >= 1; i--){
            bignum now = bignum::numcopy(y, i);
            while(x >= now){
                res.num[i]++;
                if(x == now) break;
                x = x - now;
                while(x.len && !x.num[x.len]) x.len--;
            }
        }
        while(res.len > 1 && !res.num[res.len]) res.len--;
        if(res.len == 1 && res.num[1] == 0) res.op = '+';
        return res;
    }
    friend bignum operator % (const bignum &a,const bignum &y){
        bignum x = a;
        if(x < y) return x;
        for(int i = x.len - y.len + 1; i >= 1; i--){
            bignum now = bignum::numcopy(y, i);
            while(x >= now){
                if(x == now) break;
                x = x - now;
                while(x.len && !x.num[x.len]) x.len--;
            }
        }
        if(x==y) return transform_int(0);
        return x;
    }
    static inline bignum transform_int(int x){
        bignum res;
        if(x == 0) return res;
        if(x < 0) res.op = '-', x = -x;
        res.len = 0;
        while(x){
            res.num[++res.len] = x % 10;
            x /= 10;
        }
        return res;
    }
    static inline bignum transform_string(string s){
        bignum res;
        int start = 0;
        if(s[0] == '-') {
            res.op = '-';
            start = 1;
        }
        res.len = s.size() - start;
        for(int i = start; i < s.size(); i++) {
            res.num[s.size() - i] = s[i] - '0';
        }
        while(res.len > 1 && res.num[res.len] == 0) res.len--;
        return res;
    }
    static inline void print(const bignum &x){
        if(x.op == '-') cout << "-";
        bool flag = false;
        for(int i = x.len; i >= 1; i--){
            if(x.num[i] || flag){
                cout << x.num[i];
                flag = true;
            }
        }
        if(!flag) cout << "0";
        cout << "\n";
    }
};

动态规划

主要收录了一些比较常见而且比较板的 dp。

01背包 :

//要求总重量 <= M 
for(int i=1;i<=n;i++)
	for(int j=m;j>=w[i];j--)
		dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
//要使总重量恰好为 M,可以在初始化时,将除 dp[0] 以外的 dp 值全赋为负无穷

完全背包 :

for(int i=1;i<=n;i++)
	for(int j=w[i];j<=V;j++)
		f[j]=max(f[j],f[j-w[i]]+v[i]);

多重背包 :

注 : 二进制分组优化版本。

注意这里的二进制分组不能从高位到地位拆分,而是要从低位到高位分组,确保能拼出任意数量。

for(int i=1,v,w,m;i<=n;i++){
	cin>>v>>w>>m;
	for(int j=0;j<=20;j++){
		if((1ll<<j)>m) break; 
		int nowv=(1ll<<j)*v,noww=(1ll<<j)*w;
		for(int k=V;k>=noww;k--)
			dp[k]=max(dp[k],dp[k-noww]+nowv);
		m-=(1ll<<j);
	}
	if(m>0){
		int nowv=m*v,noww=m*w;
		for(int k=V;k>=noww;k--)
			dp[k]=max(dp[k],dp[k-noww]+nowv);
	}
}

混合背包 :

for(int i=1,v,w,m;i<=n;i++){
	cin>>w>>v>>m;
	if(!m)
		for(int k=w;k<=V;k++)
			dp[k]=max(dp[k],dp[k-w]+v);
	else{
		for(int j=0;j<=20;j++){
			if((1ll<<j)>m) break; 
			int nowv=(1ll<<j)*v,noww=(1ll<<j)*w;
			for(int k=V;k>=noww;k--)
				dp[k]=max(dp[k],dp[k-noww]+nowv);
			m-=(1ll<<j);
		}
		if(m>0){
			int nowv=m*v,noww=m*w;
			for(int k=V;k>=noww;k--)
				dp[k]=max(dp[k],dp[k-noww]+nowv);
		}			
	}
}

分组背包 :

for(int k=1;k<=tot;k++){
	if(!cnt[k]) continue;
	for(int j=W;j>=0;j--)
		for(int i=1;i<=cnt[k];i++)
			if(j>=w[a[k][i]]) f[j]=max(f[j],f[j-w[a[k][i]]]+v[a[k][i]]);
}

树形背包:

滚动数组实现。

inline void dfs(int x){
    for(auto to : E[x]){
        dfs(to);
        for(int i=0;i<=siz[x]+siz[to];i++) now[i]=-inf;
        for(int i=0;i<=siz[x];i++)
            for(int j=0;j<=siz[to];j++)
                now[i+j]=max(now[i+j],f[x][i]+f[to][j]);
        for(int i=0;i<=siz[x]+siz[to];i++) f[x][i]=now[i];
        siz[x]+=siz[to];
    }
    siz[x]++;
    for(int i=siz[x];i>=1;i--)
        f[x][i]=f[x][i-1]+a[x];
    f[x][0]=0;
    return ;
}

字符串

注:Trie树 以及 Hash表(好像和字符串没什么关系?) 扔到数据结构部分了。

字符串哈希 :

inline int calc1(int l,int r){
	int ret=0;
	ret=((h1[r]-h1[l-1]*m[r-l+1]%p1)%p1+p1)%p1;
	return ret;
}
inline void init(){
	m[0]=1;
	for(int i=1;i<=top;i++) m[i]=m[i-1]*base1%p1;
	for(int i=1;i<=top;i++) h1[i]=((h1[i-1]*base1%p1+a[i])%p1+p1)%p1;	
	return ;
} 

KMP :

string s,t;
int n,m,p[N];
signed main(){
	cin>>s>>t;
	n=s.size(); s=" "+s;
	m=t.size(); t=" "+t;
	for(int i=2,j=0;i<=m;i++){
		while(j && t[i]!=t[j+1]) j=p[j];
		if(t[i]==t[j+1]) j++;
		p[i]=j;
	}
	for(int i=1,j=0;i<=n;i++){
		while(j && s[i]!=t[j+1]) j=p[j];
		if(s[i]==t[j+1]) ++j;
		if(j==m) printf("%lld\n",i-m+1),j=p[j];
	}
	for(int i=1;i<=m;i++) printf("%lld ",p[i]);
	return 0;
}

exkmp :

int n,m,z[N];
string s,t;
vector<int>pos;
signed main(){
	int tc;cin>>tc;
	while(tc--){
		cin>>s>>t;
		n=s.size(),m=t.size();
		t=" "+t+"#"+s;
		int L=1,R=0;
		for(int i=2;i<=n+m+1;i++){
			if(i>R) z[i]=0;
			else{
				int k=i-L+1;
				z[i]=min(z[k],R-i+1);
			}
			while(i+z[i]<=n+m+1 && t[i+z[i]]==t[z[i]+1]) z[i]++;
			if(i+z[i]-1>R) L=i,R=i+z[i]-1;
		}
		for(int i=m+2;i<=n+m+1;i++)
			if(z[i]==m) pos.push_back(i-m-1);
		if(pos.empty()) cout<<"-1\n-1\n";
		else{
			cout<<pos.size()<<'\n';
			for(auto u : pos) cout<<u<<' ';
			cout<<'\n';
		}
		pos.clear();
		for(int i=1;i<=n+m+1;i++) z[i]=0;
	}
    return 0;
}

Manacher :

int n,m,p[N];
string s,t;
signed main(){
    int tc=1;
    while(tc--){
        cin>>s; n=s.size(); t+='#';
        for(int i=0;i<n;i++) t+=s[i],t+='#';
        m=t.size(),t=" "+t;
        int L=0,R=0,M=0;
        for(int i=1;i<=m;i++){
            if(i>R) p[i]=1;
            else{
                int k=2*M-i;
                p[i]=min(p[k],k-L+1);
            }
            while(i-p[i]>=1 && i+p[i]<=m && t[i-p[i]]==t[i+p[i]]) ++p[i];
            if(i+p[i]-1>R) L=i-p[i]+1,R=i+p[i]-1,M=i;
        }
        int ans=0;
        for(int i=1;i<=m;i++) ans=max(ans,p[i]-1);
        cout<<ans<<'\n';
    }
    return 0;
}

最小表示法 :

int n,m;
string s,t;
signed main(){
    n=read();
    cin>>s; t=" "+s+s;
    int i=1,j=2;
    while(j<=n){
        int k=0;
        while(k<n && t[i+k]==t[j+k]) ++k;
        if(t[i+k]>t[j+k]) i+=k+1;
        else j+=k+1;
        if(i==j) ++j;
        if(i>j) swap(i,j);
    }
    for(int pos=i;pos<=i+n-1;pos++) cout<<t[pos];
	return 0;
}

数据结构

哈希表(手写):

int head[N],nxt[N],tot;
int val[N],tru[N];
inline void insert(int w,int v){
	int p=w%mod;
	for(int i=head[p];i;i=nxt[i]){
		if(val[i]==w){
			tru[i]=v;
			return ;
		}
	}
	int id=++tot;
	nxt[id]=head[p]; head[p]=id;
	val[id]=w; tru[id]=v;
	return ;
}
inline int find(int w){
	int p=w%mod;
	for(int i=head[p];i;i=nxt[i])
		if(val[i]==w) return tru[i];
	return 0;
}

并查集(路径压缩+按秩合并):

struct DSU{
	int f[N],siz[N];
	int find(int x){
		if(f[x]==x) return x;
		return f[x]=find(f[x]);
	}
	void merge(int x,int y){
		int xx=find(x),yy=find(y);
		if(xx==yy) return ;
		if(siz[xx]>siz[yy]) swap(xx,yy);
		f[xx]=yy,siz[yy]+=siz[xx];
		return ;
	} 
}dsu;

可持久化并查集:

int n,m,a[N],cnt,nowt;
struct info{ int lson,rson,val; };
struct seg_T{
	int rt[N],tot;
	info data[N];
	int newnode(int k){
		data[++tot]=data[k];
		return tot;
	}
	int build(int l,int r){
		int k=++tot;
		if(l==r) data[k].val=a[l];
		else{
			int mid=(l+r)>>1;
			data[k].lson=build(l,mid);
			data[k].rson=build(mid+1,r);
		}
		return k;
	}
	int modify(int k,int l,int r,int x,int v){
		int nx=newnode(k);
		if(l==r) data[nx].val=v;
		else{
			int mid=(l+r)>>1;
			if(x<=mid) data[nx].lson=modify(data[nx].lson,l,mid,x,v);
			else data[nx].rson=modify(data[nx].rson,mid+1,r,x,v);
		}
		return nx;
	}
	int query(int k,int l,int r,int x){
		if(l==r) return data[k].val;
		int mid=(l+r)>>1;
		if(x<=mid) return query(data[k].lson,l,mid,x);
		else return query(data[k].rson,mid+1,r,x);
	}
}Fa,Siz; 
int find(int tim,int x){
	int now=Fa.query(Fa.rt[tim],1,n,x);
	if(now==x) return x;
	return find(tim,now);
}
void merge(int u,int v){
	int ru=find(nowt,u),rv=find(nowt,v);
	if(ru==rv){
		++nowt;
		Fa.rt[nowt]=Fa.rt[nowt-1];
		Siz.rt[nowt]=Siz.rt[nowt-1];
		return ;
	}
	int sizu=Siz.query(Siz.rt[nowt],1,n,ru),sizv=Siz.query(Siz.rt[nowt],1,n,rv);
	if(sizu>sizv) swap(ru,rv);  ++nowt;
	Fa.rt[nowt]=Fa.modify(Fa.rt[nowt-1],1,n,ru,rv);
	Siz.rt[nowt]=Siz.modify(Siz.rt[nowt-1],1,n,rv,sizu+sizv);
	return ;
}

二叉堆(手写,大根堆):

int top,a[N];
inline int top_(){ return a[1]; }
inline void up(int x){
	while(x>1 && a[x]>a[x/2]) swap(a[x],a[x/2]),x/=2;
	return ;
}
inline void insert_(int x){
	a[++top]=x;
	up(top);
	return ;
}
inline void down(int x){
	while(x<=top){
		if(2*x>top) break;
		if(2*x==top){
			if(a[2*x]>a[x]) swap(a[x],a[2*x]);
			break;
		}
		int s=2*x+(a[2*x]<a[2*x+1]);
		if(a[x]<a[s]) swap(a[x],a[s]),x=s;
		else break;
	}
	return ;
}
inline void pop_(){
	a[1]=a[top--];
	down(1);
	return ;
}

单调栈:

for(int i=n;i>=1;i--){
	while(top && a[stk[top]]<=a[i]) --top;
	stk[++top]=i;
	f[i]=stk[top-1];
}

单调队列:

for(int i=1;i<=k;i++){
	while(!qmax.empty() && a[qmax.back()]<=a[i]) qmax.pop_back();
	while(!qmin.empty() && a[qmin.back()]>=a[i]) qmin.pop_back();
	qmax.push_back(i);qmin.push_back(i);
}
ansmin[++top]=a[qmin.front()];
ansmax[top]=a[qmax.front()];
for(int i=k+1;i<=n;i++){
	while(!qmax.empty() && i-qmax.front()>=k) qmax.pop_front();
	while(!qmin.empty() && i-qmin.front()>=k) qmin.pop_front();
	while(!qmax.empty() && a[qmax.back()]<=a[i]) qmax.pop_back();
	while(!qmin.empty() && a[qmin.back()]>=a[i]) qmin.pop_back();
	qmax.push_back(i),qmin.push_back(i);
	ansmin[++top]=a[qmin.front()];
	ansmax[top]=a[qmax.front()];
}

st表:

for(int i=1;i<=n;i++) a[i]=read(),st[i][0]=a[i];
for(int j=0;j<=20;j++)
    for(int i=1;i+(1<<(j+1))-1<=n;i++)
        st[i][j+1]=max(st[i][j],st[i+(1<<j)][j]);
while(m--){
    int l=read(),r=read();
    int t=log2(r-l+1);
    printf("%lld\n",max(st[l][t],st[r-(1<<t)+1][t]));
}

树状数组 :

struct Fenwick{
	int f[N];
	inline void add(int p,int v){
		for(;p<=n;p+=(p&-p)) f[p]+=v;
		return ;
	}	
	inline int ask(int p){
		int res=0;
		for(;p;p-=(p&-p)) res+=f[p];
		return res;
	}
	inline int binary_search(int x){
		int pos=0;
		for(int k=20;k>=0;k--){
			int now=(1ll<<k);
			if(pos+now<=n && f[pos+now]<=x)
				pos+=now,x-=f[pos];
		}
		return pos;
	}
}tr;

二位树状数组 :

扩展到高维同理。

struct Fenwick{
	int f[N][N];
	inline void add(int x,int y,int v){
		for(int i=x;i<=n;i+=(i&-i))
			for(int j=y;j<=m;j+=(j&-j))
				f[i][j]+=v;
		return ;
	}	
	inline int ask(int x,int y){
		int res=0;
		for(int i=x;i;i-=(i&-i))
			for(int j=y;j;j-=(j&-j))
				res+=f[i][j];
		return res;
	}
}tr;

线段树(区间乘&&加,区间求和):

struct information{int sum;};
struct Tag{int mul,add;};
information operator + (const information &x,const information &y){
	information ret;
	ret.sum=(x.sum+y.sum)%mod;
	return ret;
}
struct seg_T{
	information data[4*N];
	Tag tag[4*N];
	inline void build(int k,int l,int r){
		tag[k]={1,0};
		if(l==r){
			data[k]={a[l]%mod};
			return ;
		}
		int mid=(l+r)>>1;
		build(ls,l,mid);
		build(rs,mid+1,r);
		data[k]=data[ls]+data[rs];
		return ;
	}
	inline void lazy_tag(int k,int l,int r,int x,int y){
		tag[k].mul=tag[k].mul*x%mod;
		tag[k].add=(tag[k].add*x%mod+y)%mod;
		data[k].sum=(data[k].sum*x%mod+(r-l+1)*y%mod)%mod;
		return ;
	}
	inline void push_down(int k,int l,int r,int mid){
		if(tag[k].mul==1 && !tag[k].add) return ;
		lazy_tag(ls,l,mid,tag[k].mul,tag[k].add);
		lazy_tag(rs,mid+1,r,tag[k].mul,tag[k].add);
		tag[k].mul=1,tag[k].add=0;
		return ; 
	}
	inline void modify(int k,int l,int r,int x,int y,int d,int v){
		if(x<=l && r<=y){
			lazy_tag(k,l,r,d,v);
			return ;
		}
		int mid=(l+r)>>1;
		push_down(k,l,r,mid);
		if(x<=mid) modify(ls,l,mid,x,y,d,v);
		if(y>mid) modify(rs,mid+1,r,x,y,d,v);
		data[k]=data[ls]+data[rs];
		return ;
	}
	inline information query(int k,int l,int r,int x,int y){
		if(x<=l && r<=y) return data[k];
		int mid=(l+r)>>1;
		push_down(k,l,r,mid);
		if(y<=mid) return query(ls,l,mid,x,y);
		else if(x>mid) return query(rs,mid+1,r,x,y);
		else return query(ls,l,mid,x,y)+query(rs,mid+1,r,x,y);
	}
}T; 

线段树上二分(单点赋值,区间二分):

struct information{int Max;};
information operator + (const information &x,const information &y){
	information ret;
	ret.Max=max(x.Max,y.Max);
	return ret;
}
struct seg_T{
	information data[4*N];
	inline void build(int k,int l,int r){
		if(l==r){
			data[k]={a[l]};
			return ;
		}
		int mid=(l+r)>>1;
		build(ls,l,mid);
		build(rs,mid+1,r);
		data[k]=data[ls]+data[rs];
		return ;
	}
	inline void change(int k,int l,int r,int x,int d){
		if(l==r){
			data[k]={d};
			return ;
		}
		int mid=(l+r)>>1;
		if(x<=mid) change(ls,l,mid,x,d);
		else change(rs,mid+1,r,x,d);
		data[k]=data[ls]+data[rs];
		return ;
	}
	inline int search(int k,int l,int r,int x,int y,int d){
		if(data[k].Max<d) return -1;
		if(l==r) return l;
		int mid=(l+r)>>1,res=0;
		if(x<=mid){
			res=search(ls,l,mid,x,y,d);
			if(res!=-1) return res;
		}
		if(y>mid) res=search(rs,mid+1,r,x,y,d);
		return res;
	}
}T; 

可持久化数组 :

struct info{ int lson,rson,val; };
struct seg_T{
	int rt[N],tot;
	info data[N];
	int newnode(int k){
		data[++tot]=data[k];
		return tot;
	}
	int build(int l,int r){
		int k=++tot;
		if(l==r) data[k].val=a[l];
		else{
			int mid=(l+r)>>1;
			data[k].lson=build(l,mid);
			data[k].rson=build(mid+1,r);
		}
		return k;
	}
	int modify(int k,int l,int r,int x,int v){
		int nx=newnode(k);
		if(l==r) data[nx].val=v;
		else{
			int mid=(l+r)>>1;
			if(x<=mid) data[nx].lson=modify(data[nx].lson,l,mid,x,v);
			else data[nx].rson=modify(data[nx].rson,mid+1,r,x,v);
		}
		return nx;
	}
	info query(int k,int l,int r,int x){
		if(l==r) return data[k];
		int mid=(l+r)>>1;
		if(x<=mid) return query(data[k].lson,l,mid,x);
		else return query(data[k].rson,mid+1,r,x);
	}
}T; 

可持久化线段树(主席树):

静态区间第 \(k\) 小。

struct info{ int lson,rson,sum; };
struct seg_T{
	info data[N];
	int rt[N],tot;
	int newnode(int k){
		data[++tot]=data[k];
		return tot;
	}
	int add(int k,int l,int r,int x,int v){
		int nx=newnode(k); data[nx].sum+=v;
		if(l!=r){
			int mid=(l+r)>>1;
			if(x<=mid) data[nx].lson=add(data[nx].lson,l,mid,x,v);
			else data[nx].rson=add(data[nx].rson,mid+1,r,x,v);
		}
		return nx;
	}
	int query(int k1,int k2,int l,int r,int x){//binary search
		if(l==r) return l;
		int mid=(l+r)>>1;
		int lsum=data[data[k2].lson].sum-data[data[k1].lson].sum;
		if(lsum>=x) return query(data[k1].lson,data[k2].lson,l,mid,x);
		else return query(data[k1].rson,data[k2].rson,mid+1,r,x-lsum);
	}
}T; 

普通平衡树:

FHQ treap :

mt19937 mrand(1);
struct info{ int l,r,val,rnd,siz; };
struct FHQ_treap{
	int tot,rt;
	info data[N];
	int newnode(int x){
		int now=(int)mrand(); 
		data[++tot]={0,0,x,now,1};
		return tot;
	}
	void update(int pos){
		data[pos].siz=1;
		if(data[pos].l) data[pos].siz+=data[data[pos].l].siz;
		if(data[pos].r) data[pos].siz+=data[data[pos].r].siz;
		return ;
	}
	int merge(int l,int r){
		if(!l || !r) return l+r;
		int ret=0;
		if(data[l].rnd<data[r].rnd){
			data[l].r=merge(data[l].r,r);
			ret=l; update(l);
		}
		else{
			data[r].l=merge(l,data[r].l);
			ret=r; update(r);
		}
		return ret;
	}
	void split(int pos,int key,int &l,int &r){// < key的为左树 
		if(!pos){ l=r=0; return ; }
		if(data[pos].val<key) l=pos,split(data[pos].r,key,data[pos].r,r);
		else r=pos,split(data[pos].l,key,l,data[pos].l);
		update(pos);
		return ;
	}
	void insert_(int x){
		int l,r,now=newnode(x); 
		split(rt,x,l,r);
		rt=merge(l,merge(now,r));
		return ;
	}
	void delete_(int x){
		int l,mid,r;
		split(rt,x+1,l,r); split(l,x,l,mid);
		mid=merge(data[mid].l,data[mid].r);
		rt=merge(merge(l,mid),r);
		return ;
	}
	int kth(int pos,int k){
		int ans=0;
		while(true){
			if(data[data[pos].l].siz+1==k) return data[pos].val;
			else if(data[data[pos].l].siz+1<k){
				k=k-(data[data[pos].l].siz+1);
				pos=data[pos].r;
			}
			else pos=data[pos].l;
		}
		return 0;
	}
	int pre_qry(int x){
		int l,r; split(rt,x,l,r);
		int pos=l,ret=0;
		while(data[pos].r) pos=data[pos].r;
		ret=data[pos].val; rt=merge(l,r);
		return ret;
	}
	int suf_qry(int x){
		int l,r; split(rt,x+1,l,r);
		int pos=r,ret=0;
		while(data[pos].l) pos=data[pos].l;
		ret=data[pos].val; rt=merge(l,r);
		return ret;
	}
}T;

文艺平衡树:

FHQ treap :

mt19937 mrand(1);
int n,m;
struct info{ int l,r,val,rnd,siz,id; };
struct Tag{ bool rev;  };
struct FHQ_treap{
	int tot,rt;
	Tag tag[N];
	info data[N];
	int newnode(int x,int idx){
		int now=(int)mrand(); 
		data[++tot]={0,0,x,now,1,idx};
		tag[tot].rev=0;
		return tot;
	}
	void update(int pos){
		data[pos].siz=1;
		if(data[pos].l) data[pos].siz+=data[data[pos].l].siz;
		if(data[pos].r) data[pos].siz+=data[data[pos].r].siz;
		return ;
	}
	void lazy_tag(int pos){
		tag[pos].rev^=1;
		swap(data[pos].l,data[pos].r);
		return ;
	}
	void push_down(int pos){
		if(!tag[pos].rev) return ;
		lazy_tag(data[pos].l); lazy_tag(data[pos].r);
		tag[pos].rev=0;
		return ;
	}
	int merge(int l,int r){
		if(!l || !r) return l+r;
		int ret=0;
		if(data[l].rnd<data[r].rnd){
			push_down(l);
			data[l].r=merge(data[l].r,r);
			ret=l; update(l);
		}
		else{
			push_down(r);
			data[r].l=merge(l,data[r].l);
			ret=r; update(r);
		}
		return ret;
	}
	void split(int pos,int key,int &l,int &r){// siz <= key 的为左树 
		if(!pos){ l=r=0; return ; }
		push_down(pos);
		if(data[data[pos].l].siz+1<=key) l=pos,split(data[pos].r,key-(data[data[pos].l].siz+1),data[pos].r,r);
		else r=pos,split(data[pos].l,key,l,data[pos].l);
		update(pos);
		return ;
	}
}T;
void print(int pos){
	T.push_down(pos);
	if(T.data[pos].l) print(T.data[pos].l);
	cout<<T.data[pos].id<<" ";
	if(T.data[pos].r) print(T.data[pos].r);
	return ;
}

可持久化平衡树:

Submission.

mt19937 mrand(1);
struct info{
	int lson,rson;
	int val,rnd,siz;
}; 
struct FHQ_treap{
	int rt[N],tot;
	info data[N];
	int cpynode(int k){
		data[++tot]=data[k];
		return tot;
	}
	int newnode(int x){
		int now=(int)mrand();
		data[++tot].rnd=now;
		data[tot].val=x,data[tot].siz=1;
		return tot;
	}
	void update(int pos){
		data[pos].siz=1;
		if(data[pos].lson) data[pos].siz+=data[data[pos].lson].siz;
		if(data[pos].rson) data[pos].siz+=data[data[pos].rson].siz;
		return ;
	}
	void split(int pos,int key,int &l,int &r){// val < key 的为左树 
		if(!pos){ l=r=0; return ; }
		if(data[pos].val<key){
			int nx=cpynode(pos);
			split(data[nx].rson,key,data[nx].rson,r);
			l=nx; update(nx);
		}
		else{
			int nx=cpynode(pos);
			split(data[nx].lson,key,l,data[nx].lson);
			r=nx; update(nx);
		}
		return ;
	}
	int merge(int l,int r){
		if(!l || !r) return l+r;
		int ret=0;
		if(data[l].rnd<data[r].rnd){
			int nx=cpynode(l);
			data[nx].rson=merge(data[nx].rson,r);
			ret=nx; update(nx);
		}
		else{
			int nx=cpynode(r);
			data[nx].lson=merge(l,data[nx].lson);
			ret=nx; update(nx);
		}
		return ret;
	}
	int kth(int pos,int k){
		while(true){
			int sz=data[data[pos].lson].siz+1;
			if(sz==k) return data[pos].val;
			else if(sz<k) pos=data[pos].rson,k-=sz;
			else pos=data[pos].lson;
		}
		return 0;
	}
}T;
posted @ 2026-07-25 15:18  lmx_rp++  阅读(9)  评论(0)    收藏  举报