走~走走~走走走走​🚶‍♂️🚶‍♂️🚶‍♂️

数据结构板子


并查集

判断集合,合并集合,比如图论中的kruskal,连通分支等。

//int fa[N],siz[N];
void init_set(int n){//初始化
    for(int i=1;i<=n;++i){
        fa[i]=i,siz[i]=1;
    }
}
int find(int x){//路径压缩
    return fa[x]==x?x:(fa[x]=find(fa[x]));
}
void unionfa(int x,int y){//启发式合并
    int parent_x=find(x),parent_y=find(y);
    if(parent_x==parent_y){
        return;
    }
    if(siz[parent_x]>siz[parent_y]){
        swap(parent_x,parent_y);
    }//按照节点集合大小,保证小的和到大的里面。
    fa[parent_x]=parent_y;
    siz[parent_y]+=siz[parent_x];
}

ST表

$\Theta(nlogn)预处理,\Theta(1)查询$

可重复贡献———若对某种运算$opt$,有:$xopt x=x$,例如$gcd(x,x)=x,max(x,x)=x$,则类似的区间查询,比如区间gcd,区间最大值,且$opt$满足结合律$aopt(boptc)=(aoptb)optc$,则可以使用ST表进行区间查询。
但比如区间和,opt行为就会计算两次,还是不行捏。
DP:$f(i,j)=max[i,i+2^j-1]$
$f(i,0)=max[i,i]=i$
->
$f(i,j)=max(f(i,j-1),f(i+2^{j-1},j-1))$

//以最大值为例
//#define N 2000001
const int maxlog=21;
int st[N][maxlog],logn[N];
void init_st(int n){
    logn[1]=0;
    logn[2]=1;
    for(int i=3;i<N;++i){
        logn[i]=logn[i>>1]+1;
    }
}
void st_process(int total){
    init_st();
    for(int i=1;i<=n;++i){
        cin>>st[i][0];
    }
}

树状数组

int tree[N],diff[N];
int lowbit(int x){
    return x&-x;
}
void add(int x,int k,int n){
    int tem=x*k;
    while(x<=n){
        tree[x]+=k,diff[x]+=tem;
        x+=lowbit(x);   
    }
}
void add_range(int,l,int r,int k){
    add(l,k),add(r+1,-v);
}
long long int get_sum_range(intl,int r){
    return (r+1ll)*getpre(r,tree)-1ll*l*getpre(l-1,tree)-
    (getpre(r,diff)-getpre(l-1,diff));
}
int getpre(int x,int *tree){
    int cnt=0;
    while(x) {
        cnt+=tree[x];
        x-=lowbit(x);
    }
    return cnt;
}

Author: ZzzRemake
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source ZzzRemake !
Comment
  TOC