简单数据结构模板汇总

不包括字符串和图论内容。
某种意义上算是“简单”数据结构……
代码压行警告qwq

如果存在与数据结构有关的经典算法,也会予以列出。

1. 单调队列

const int maxn=1000010;
int n,k,cnt,a[maxn],minans[maxn],maxans[maxn];
deque<int> minint,maxint;
void push(int pos)
{
    while(!minint.empty()&&minint.front()<=pos-k)minint.pop_front();
    while(!maxint.empty()&&maxint.front()<=pos-k)maxint.pop_front();
    while(!minint.empty()&&a[minint.back()]>=a[pos])minint.pop_back();
    while(!maxint.empty()&&a[maxint.back()]<=a[pos])maxint.pop_back();
    minint.push_back(pos);maxint.push_back(pos);
}
//......
for(int i=1;i<k;i++)push(i);
for(int i=k;i<=n;i++)
{
    push(i);cnt++;
    minans[cnt]=a[minint.front()];
    maxans[cnt]=a[maxint.front()];
}

2. 单调栈

const int maxn=3000010;
int n,a[maxn],ans[maxn];
stack<int> st;
?for(int i=n;i>=1;i--)
{
    while(!st.empty()&&a[st.top()]<=a[i])st.pop();
    if(!st.empty())ans[i]=st.top();
    st.push(i);
}

3. 并查集

路径压缩+按秩合并

const int maxn=100010;
int n,fa[maxn],siz[maxn];
void init(int xx){for(int i=1;i<=xx;i++){fa[i]=i;siz[i]=1;}}
int find(int xx){return fa[xx]==xx?xx:fa[xx]=find(fa[xx]);}
int query(int xx,int yy){return find(xx)==find(yy);}
void merge(int xx,int yy)
{
    int fx=find(xx),fy=find(yy);
    if(fx==fy)return;
    if(siz[fx]<siz[fy]){fa[fx]=fy;siz[fy]+=siz[fx];fa[xx]=fy;}
    else{fa[fy]=fx;siz[fx]+=siz[fy];fa[yy]=fx;}
}

4. ST表

int n,m,ans,l,r,k,lg2[100010],st[100010][20];
for(int i=2;i<100010;i++)lg2[i]=lg2[i/2]+1;
for(int i=1;i<=n;i++)scanf("%d",&st[i][0]);
for(int j=1;j<=lg2[n];j++)
	for(int i=1;i+(1<<(j-1))<=n;i++)
		st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
for(int i=1;i<=m;i++)
{
	scanf("%d%d",&l,&r);k=lg2[r-l+1];
	ans=max(st[l][k],st[r-(1<<k)+1][k]);
	printf("%d\n",ans);
}

5. 树状数组

5.1 树状数组模板

int n,m,a[500010];
inline int lowbit(int x){return x&(-x);}
inline void add(int x,int k){while(x<=n)a[x]+=k,x+=lowbit(x);}
inline int query(int pos)
{
    int ans=0;
    while(pos)ans+=a[pos],pos-=lowbit(pos);
    return ans;
}

5.2 树状数组求逆序对

struct node{int pos,x;}a[500010];
int rk[500010];
bool cmp(node xx,node yy)
{
    if(xx.x!=yy.x)return xx.x<yy.x;
    return xx.pos<yy.pos;
}
class Bittree
{
public:
    int num=500010,datas[500010];
    int lowbit(int x){return x&(-x);}
    void add(int x,int k){while(x<=num)datas[x]+=k,x+=lowbit(x);}
    int query(int pos)
    {
        int ans=0;
        while(pos)ans+=datas[pos],pos-=lowbit(pos);
        return ans;
    }
}tree;
int n,ans;
//......
for(int i=1;i<=n;i++){scanf("%lld",&a[i].x);a[i].pos=i;}
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)rk[a[i].pos]=i;
for(int i=1;i<=n;i++){tree.add(rk[i],1);ans+=i-tree.query(rk[i]);}

6. 线段树

6.1 复杂标记线段树

以线段树2为例。高度模式化的代码。

const int maxn=100010;
int n,m,p,a[maxn];
struct node{int l,r,val,add,mul;}tree[maxn<<2];
void pushup(int x)
{
    int lson=x<<1,rson=lson|1;
    tree[x].val=(tree[lson].val+tree[rson].val)%p;
}
void pushmul(int x,int k)
{
    tree[x].val*=k;tree[x].val%=p;
    tree[x].mul*=k;tree[x].mul%=p;
    tree[x].add*=k;tree[x].add%=p;
}
void pushadd(int x,int k)
{
    tree[x].val+=k*(tree[x].r-tree[x].l+1);tree[x].val%=p;
    tree[x].add+=k;tree[x].add%=p;
}
void pushdown(int x)
{
    int lson=x<<1,rson=lson|1;
    if(tree[x].l==tree[x].r)return;
    if(tree[x].mul!=1)//if的先后是按标记的优先级排的
    {
        pushmul(lson,tree[x].mul);
        pushmul(rson,tree[x].mul);
        tree[x].mul=1;
    }
    if(tree[x].add!=0)
    {
        pushadd(lson,tree[x].add);
        pushadd(rson,tree[x].add);
        tree[x].add=0;
    }
}
void build(int x,int l,int r)
{
    tree[x]=(node){l,r,0,0,1};
    if(l==r){tree[x].val=a[l];return;}
    int mid=(tree[x].l+tree[x].r)>>1,lson=x<<1,rson=lson|1;
    build(lson,l,mid);build(rson,mid+1,r);
    pushup(x);
}
void modify_mul(int x,int l,int r,int k)
{
    pushdown(x);
    if(l<=tree[x].l&&r>=tree[x].r){pushmul(x,k);return;}
    int mid=(tree[x].l+tree[x].r)>>1,lson=x<<1,rson=lson|1;
    if(l<=mid)modify_mul(lson,l,r,k);
    if(r>mid)modify_mul(rson,l,r,k);
    pushup(x);
}
void modify_add(int x,int l,int r,int k)
{
    pushdown(x);
    if(l<=tree[x].l&&r>=tree[x].r){pushadd(x,k);return;}
    int mid=(tree[x].l+tree[x].r)>>1,lson=x<<1,rson=lson|1;
    if(l<=mid)modify_add(lson,l,r,k);
    if(r>mid)modify_add(rson,l,r,k);
    pushup(x);
}
int query_sum(int x,int l,int r)
{
    pushdown(x);
    if(l<=tree[x].l&&r>=tree[x].r)return tree[x].val;
    int mid=(tree[x].l+tree[x].r)>>1,lson=x<<1,rson=lson|1,ans=0;
    if(l<=mid){ans+=query_sum(lson,l,r);ans%=p;}
    if(r>mid){ans+=query_sum(rson,l,r);ans%=p;}
    return ans;
}

6.2 动态开点权值线段树

6.3 扫描线

6.4 二维线段树

7. 树链剖分

7.1 轻重链剖分

7.2 dsu on tree

7.3 长链剖分

8. 分块相关

见这里

9. 左偏树

10. 平衡树

10.1 普通平衡树

10.1.1 替罪羊树版
10.1.2 fhq_treap版
10.1.3 splay版

10.2 文艺平衡树

10.2.1 fhq_treap版
10.2.2 splay版

11. 可持久化数据结构

11.1 主席树

11.2 可持久化数组

11.3 可持久化并查集

11.4 可持久化平衡树

11.5 可持久化文艺平衡树

简单数据结构模板汇总

上一篇:关于dijkstra算法的一点理解


下一篇:《JavaScript高级程序设计》学习笔记12篇