【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 ;
}
可持久化平衡树:
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;

浙公网安备 33010602011771号