[模板] 一些模板

· · 算法·理论

一些常用的算法 \text{or} 数据结构模板

by jr_zch

\text{Store - Wagner}

void wagner(int turn){
    if(turn<=1) return ;
    for(int i=1;i<=n;i++) is[i]=w[i]=0;
    int sum,id,lst;
    for(int i=1;i<=turn;i++){
        lst=id,sum=-1,id=0;
        for(int j=1;j<=n;j++) if(!del[j]&&!is[j]&&w[j]>sum) sum=w[j],id=j;
        is[id]=1; 
        for(int j=1;j<=n;j++) if(!del[j]&&!is[j]) w[j]+=mp[id][j];
    }
    ans=min(ans,sum);
    del[lst]=1;
    for(int i=1;i<=n;i++){
        mp[id][i]+=mp[lst][i];
        mp[i][id]+=mp[i][lst];
    }
    wagner(turn-1);
    return ;
}

\text{PAM}

struct pam{
    int len,tot,lst;
    int s[maxn],l[maxn],fail[maxn],to[maxn][26];
    void init(){
        tot=2,lst=1;
        l[1]=-1,l[2]=0;
        fail[1]=fail[2]=1;
        memset(s,-1,sizeof(s));
        return ;
    }
    int calc(int x){
        while(s[len-l[x]-1]!=s[len]) x=fail[x];
        return x;
    }
    void insert(int p){
        s[++len]=p;
        int pre=calc(lst);
        if(to[pre][p]){
            lst=to[pre][p];
            return ;
        }else lst=to[pre][p]=++tot;
        l[tot]=l[pre]+2;
        if(pre==1) fail[tot]=2;
        else fail[tot]=to[calc(fail[pre])][p];
        return ;
    }
};

异或线性基

struct basis{
    int emp,len;
    int b[66];
    basis(int _len=0){
        emp=len=_len;
        memset(b,0,sizeof(b));
    }
    bool insert(int x){
        if(!emp) return 0;
        for(int i=len;i>=0;i--){
            if(!x) return 0;
            if(x>>i&1ll){
                if(b[i]) x^=b[i];
                else return (--emp)+(b[i]=x);
            }
        }
        return 0;
    }
    int query(){
        int res=0;
        for(int i=len;i>=0;i--) if(res>>i&1ll^1ll) res^=b[i];
        return res;
    }
}f[maxn];

basis merge(basis x,basis y){
    basis res=x;
    for(int i=x.len;i>=0;i--) if(y.b[i]) res.insert(y.b[i]);
    return res;
}

\text{Cipolla}

struct comple{
    int a,b,sqr,mod;
    comple(int _a=0,int _b=0,int _sqr=0,int _mod=1){
        a=_a,b=_b;
        sqr=_sqr,mod=_mod;
    }
    comple operator *(const comple &x) const{
        return (comple){(a*x.a+b*x.b%mod*sqr)%mod,(a*x.b+b*x.a)%mod,sqr,mod};
    }
};

int qpow(int x,int y,int mod){
    int res=1;
    while(y){
        if(y&1ll) res=res*x%mod;
        x=x*x%mod,y>>=1ll;
    }
    return res;
}

int qpow(comple x,int y){
    comple res=comple(1,0,x.sqr,x.mod);
    while(y){
        if(y&1ll) res=res*x;
        x=x*x,y>>=1ll;
    }
    return res.a;
}

int cipolla(int a,int p){
    a=(a%p+p)%p;
    if(!a) return 0;
    if(p==2) return 1;
    if(qpow(a,p-1>>1ll,p)==p-1) return -1;
    int b=rand()%p;
    while(qpow((b*b-a+p)%p,p-1>>1ll,p)!=p-1) b=rand()%p;
    comple now=(comple){b,1,(b*b-a+p)%p,p};
    int ans=qpow(now,p+1>>1ll);
    return min(ans,p-ans);
}

\text{Miller Rabin / Pollard Rho}

const int pri[8]={0,2,325,9375,28178,450775,9780504,1795265022};

inline int f(int x,int c,int mod){
    return (x*x%mod+c)%mod;
}

inline int abs(int x){
    return x<0?-x:x;
}

inline int gcd(int x,int y){
    return y==0?x:gcd(y,x%y);
}

int qpow(int x,int y,int mod){
    int res=1;
    while(y){
        if(y%2) res=res*x%mod;
        x=x*x%mod,y/=2;
    }
    return res;
}

bool miller(int num){
    if(num<2||(num>2&&num%2==0)) return 0;
    if(num==2||num==3||num==5||num==7||num==11) return 1;
    int now=num-1,t=0;
    while(!(now%2)) now/=2,t++;
    for(int i=1;i<=7;i++){
        int x=pri[i]%num,mul=qpow(x,now,num),j=0;
        if(!x||x==1||x==num-1||mul==1) continue;
        while(j<t){
            if(mul==num-1) break;
            mul=mul*mul%num,j++;
        }
        if(j==t) return 0;
    }
    return 1;
}

void pollard(int num){
    if(miller(num)){
        ans=max(ans,num);
        return ;
    }
    if(!(num%2)){
        ans=max(ans,(int)2);
        pollard(num/2);
        return ;
    }
    int res=0;
    while(1){
        int st=rand()%num,c=rand()%(num-1)+1;
        for(int t=1,mul=1,x=st,y=st;;t*=2,mul=1,x=y){
            for(int i=1;i<=t;i++){
                y=f(y,c,num),mul=mul*abs(x-y)%num;
                if(!mul) break;
                if(i%127==0){
                    int d=gcd(mul,num);
                    if(d>1){
                        pollard(d),pollard(num/d);
                        return ;
                    }
                }
            }
            if(!mul) break;
            int d=gcd(mul,num);
            if(d>1){
                pollard(d),pollard(num/d);
                return ;
            }
        }
    }
    return ;
}

\text{BSGS}

int bsgs(int x,int r,int mod){
    int lim=sqrt(mod);
    mp.clear(),x%=mod,r%=mod;
    if(!x){
        if(r) return -1;
        else return 1;
    }
    int now=1;
    for(int i=0;i<=lim;i++){
        mp.insert(now*r%mod,i);
        if(i<lim) now=now*x%mod;
    }
    for(int i=1,j=now;i<=mod/lim+1;i++,j=j*now%mod) if(mp.count(j)) return i*lim-mp[j];
    return -1;
}

\text{SSP}

bool spfa(){
    for(int i=1;i<=ed;i++) dis[i]=inf,flow[i]=0;
    dis[st]=0,flow[st]=inf,q.push(st);
    while(!q.empty()){
        int u=q.front();q.pop();
        vis[u]=0;
        for(int i=last[u];~i;i=nxt[i]){
            int v=to[i];
            if(dis[v]>dis[u]+c[i]&&w[i]){
                dis[v]=dis[u]+c[i],pre[v]=i^1;
                flow[v]=min(flow[u],w[i]);
                if(!vis[v]) q.push(v),vis[v]=1;
            }
        }
    }
    return flow[ed];
}

void mcmf(){
    ass+=flow[ed];
    for(int i=ed;i!=st;i=to[pre[i]]){
        w[pre[i]]+=flow[ed];
        w[pre[i]^1]-=flow[ed];
        ans+=c[pre[i]^1]*flow[ed];
    }
    return ;
}

\text{Dinic}

int dinic(int u,int inw){
    if(u==ed||!inw) return inw;
    int outw=0;
    for(int i=cur[u];~i;i=nxt[i]){
        int v=to[i];
        cur[u]=i;
        if(dis[v]==dis[u]+1&&w[i]){
            int val=dinic(v,min(inw-outw,w[i]));
            outw+=val;
            w[i]-=val;
            w[i^1]+=val;
            if(inw==outw) return outw;
        }
    }
    return outw;
}

哈希表

struct hash_table{
    int cnt;
    int a[mod],l[mod],r[mod],nxt[mod];
    vector<int> cl;
    void init(){
        cnt=0,cl.clear();
        memset(a,0,sizeof(a));
        return ;
    }
    void clear(){
        cnt=0;
        for(int i:cl) a[i]=0;
        cl.clear();
        return ;
    }
    inline int get(int x){
        return x%mod;
    }
    void insert(int key,int val){
        int now=get(key);
        for(int i=a[now];i;i=nxt[i]){
            if(l[i]==key){
                r[i]=val;
                return ;
            }
        }
        if(!a[now]) cl.push_back(now);
        l[++cnt]=key,r[cnt]=val,nxt[cnt]=a[now],a[now]=cnt;
        return ;
    }
    int operator [](int key){
        int now=get(key);
        for(int i=a[now];i;i=nxt[i]) if(l[i]==key) return r[i];
        return 0;
    }
    bool count(int key){
        int now=get(key);
        for(int i=a[now];i;i=nxt[i]) if(l[i]==key) return 1;
        return 0;
    }
};

\text{AC} 自动机

int trnode;
int to[maxl][26],fail[maxl],is[maxl];
queue<int> q;

void insert(int id){
    int now=0;
    for(int i=1;i<=l[id];i++){
        int nxt=s[id][i]-'a';
        if(!to[now][nxt]) to[now][nxt]=++trnode;
        now=to[now][nxt];
    }
    is[now]++;
    return ;
}

void build(){
    q.push(0);
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=0;i<26;i++){
            int v=to[u][i];
            if(v){
                if(!u) fail[v]=0;
                else fail[v]=to[fail[u]][i];
                q.push(v);
            }else to[u][i]=to[fail[u]][i];
        }
    }
    return ;
}

\text{ISAP}

int isap(int u,int inw){
    if(u==ed) return inw;
    int outw=0;
    for(int i=cur[u];i<e[u].size();i++){
        int v=e[u][i];
        cur[u]=i;
        if(dis[u]==dis[v]+1&&mp[u][v]){
            int val=isap(v,min(inw-outw,mp[u][v]));
            outw+=val;
            mp[u][v]-=val;
            mp[v][u]+=val;
            if(dis[st]==ed||inw==outw) return outw;
        }
    }
    c[dis[u]]--;
    if(!c[dis[u]]) dis[st]=ed;
    dis[u]++;
    c[dis[u]]++;
    cur[u]=0;
    return outw;
}

李超线段树——直线

struct line{
    bool p;
    int k,b;
    int gety(int x){
        return p?k*x+b:-inf;
    }
}data[maxn<<5];

void update(int &rt,int l,int r,line val){
    if(!rt) rt=++trnode;
    if(l==r){
        int u=data[rt].gety(l),v=val.gety(l);
        if(v>u) data[rt]=val; 
        return ;
    }
    int mid=l+r>>1ll;
    if(data[rt].p){
        int ul=data[rt].gety(l),ur=data[rt].gety(r);
        int vl=val.gety(l),vr=val.gety(r);
        if(ul>=vl&&ur>=vr) return ;
        if(vl>=ul&&vr>=ur){
            data[rt]=val;
            return ;
        }
        int u=data[rt].gety(mid),v=val.gety(mid);
        if(v>u){
            swap(data[rt],val),swap(u,v);
            swap(ul,vl),swap(ur,vr);
        }
        if(vl>ul) update(ls[rt],l,mid,val);
        else update(rs[rt],mid+1,r,val);
    }else data[rt]=val;
    return ;
}

int query(int rt,int l,int r,int x){
    if(!rt) return -inf;
    if(l==r) return data[rt].gety(x);
    int mid=l+r>>1ll,res=data[rt].gety(x);
    if(x<=mid) return max(res,query(ls[rt],l,mid,x));
    else return max(res,query(rs[rt],mid+1,r,x));
}

\text{KMP}

int find(int lens,int lent,char *s,char *t){
    t[lent+1]='#';
    for(int i=lent+2;i<=lens+lent+1;i++) t[i]=s[i-lent-1];
    for(int i=2;i<=lens+lent+1;i++){
        int now=pre[i-1];
        while(now&&t[i]!=t[now+1]) now=pre[now];
        pre[i]=now+(t[i]==t[now+1]);
    }
    for(int i=lent+2;i<=lens+lent+1;i++) if(pre[i]==lent) return i-lent-1;
    return -1;
}

最小表示法

int get(int lens,int *s){
    int i=1,j=2,k=0;
    while(i<=lens&&j<=lens&&k<lens){
        if(s[i+k]>s[j+k]) i+=k+1,k=0;
        else if(s[i+k]<s[j+k]) j+=k+1,k=0;
        else k++;
        if(i==j) i++;
    }
    return min(i,j);
}

高斯消元

int gauss(int n,int m){
    int i=1,j=1,r;
    while(i<=n&&j<=m){
        r=i;
        for(int k=i+1;k<=n;k++) if(fabs(a[k][j])>fabs(a[r][j])) r=k;
        if(fabs(a[r][j])>eps){
            for(int k=1;k<=m+1;k++) swap(a[i][k],a[r][k]);
            for(int k=i+1;k<=n;k++){
                double val=a[k][j]/a[i][j];
                for(int l=j;l<=m+1;l++) a[k][l]-=a[i][l]*val;
            }
            i++;
        }
        j++;
    }
    for(int k=i;k<=n;k++) if(fabs(a[k][m+1])>0) return -1;
    if(i<=m) return 0;
    for(int i=m;i;i--){
        x[i]=a[i][m+1];
        for(int j=i+1;j<=m;j++) x[i]-=a[i][j]*x[j];
        x[i]/=a[i][i];
    }
    return 1;
}

特殊高斯消元 - 线性异或方程

bitset<maxn> a[maxn];

int gauss(int n,int m){
    int i=1,j=1,r;
    while(i<=n&&j<=m){
        r=i;
        for(int k=i+1;k<=n;k++){
            if(a[r][j]) break;
            if(a[k][j]>a[r][j]) r=k;
        }
        if(a[r][j]){
            if(i!=r) swap(a[i],a[r]);
            for(int k=i+1;k<=n;k++) if(a[k][j]) a[k]^=a[i];
            i++;
        }
        j++;
    }
    for(int k=i;k<=n;k++) if(a[k][m+1]) return 0;
    if(i<=m) return -1;
    for(int i=m;i;i--){
        x[i]=a[i][m+1];
        for(int j=i+1;j<=m;j++) x[i]^=a[i][j]*x[j];
    }
    return 1;
}

\text{ExCRT / ExGCD}

struct node{
    int r,p;
}q[maxn];

int exgcd(int a,int b,int &x,int &y){
    if(!b){
        x=1,y=0;
        return a;
    }
    int d=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}

int excrt(node q[],int tot,int limit){
    int res=q[1].r,now=q[1].p;
    for(int i=2,x,y;i<=tot;i++){
        int d=exgcd(now,q[i].p,x,y);
        if((q[i].r-res)%d) return -1;
        x*=(q[i].r-res)/d,x=(x%(q[i].p/d)+q[i].p/d)%(q[i].p/d);
        res+=now*x,now*=q[i].p/d;
        if(res>limit) break;
    }
    for(int i=1;i<=tot;i++) if(res%q[i].p!=q[i].r) return -1;
    return res;
}

\text{ExLucas}

int qpow(int x,int y,int mod){
    if(!y) return 1;
    if(y==1) return x;
    int val=qpow(x,y>>1ll,mod);
    if(y&1ll) return val*val%mod*x%mod;
    else return val*val%mod;
}

int exgcd(int a,int b,int &x,int &y){
    if(!b){
        x=1,y=0;
        return a;
    }
    int d=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return d;
}

int excrt(){
    int res=q[1].r,now=q[1].m;
    for(int i=2,x,y;i<=idx;i++){
        int d=exgcd(now,q[i].m,x,y);
        if((q[i].r-res)%d) return -1;
        x*=(q[i].r-res)/d,x=(x%(q[i].m/d)+q[i].m/d)%(q[i].m/d);
        res+=now*x,now*=q[i].m/d;
    }
    return res;
}

int get(int val,int mod){
    int sum=0,now=mod;
    while(val/now) sum+=val/now,now*=mod;
    return sum;
}

int calc(int val,int p,int mod){
    if(val<=p) return pfac[val];
    return calc(val/p,p,mod)*qpow(pfac[mod],val/mod,mod)%mod*pfac[val%mod]%mod;
}

void init(int p,int mod){
    pfac[0]=1;
    for(int i=1;i<=mod;i++){
        if(i%p) pfac[i]=pfac[i-1]*i%mod;
        else pfac[i]=pfac[i-1];
    }
    return ;
}

int exlucas(int x,int y,int mod){
    if(x<y) return 0;
    int byx,byy,byz,phi,rmod=mod;
    idx=0;
    for(int i=2;i*i<=mod&&i<=1e6;i++){
        if(!(rmod%i)){
            int now=1;
            while(!(rmod%i)) rmod/=i,now*=i;
            q[++idx]=(node){0,now,i};
        }
    }
    if(rmod>1) q[++idx]=(node){0,rmod,rmod};
    for(int i=1;i<=idx;i++){
        init(q[i].p,q[i].m),phi=q[i].m-q[i].m/q[i].p-1;
        byx=get(x,q[i].p),byy=get(y,q[i].p),byz=get(x-y,q[i].p);
        q[i].r=calc(x,q[i].p,q[i].m)*qpow(calc(y,q[i].p,q[i].m),phi,q[i].m)%q[i].m*qpow(calc(x-y,q[i].p,q[i].m),phi,q[i].m)%q[i].m*qpow(q[i].p,byx-byy-byz,q[i].m)%q[i].m;
    }
    return excrt();
}

\text{Dijkstra}

int dis[maxn];
bool vis[maxn];
struct node{
    int to,len;
    bool operator<(const node &a) const{
        return len>a.len;
    }
};
vector<node> e[maxn];
priority_queue<node> q;

void dijkstra(int st){
    memset(dis,0x3f,sizeof(dis));
    dis[st]=0;
    q.push((node){st,0});
    while(!q.empty()){
        int u=q.top().to;q.pop();
        if(vis[u]) continue;
        vis[u]=1;
        for(int i=0;i<e[u].size();i++){
            int v=e[u][i].to; 
            if(dis[v]>dis[u]+e[u][i].len){
                dis[v]=dis[u]+e[u][i].len;
                q.push((node){v,dis[v]});
            }
        }
    }
    return ;
}

\text{SPFA}

void spfa(){
    for(int i=1;i<=n;i++) dis[i]=inf;
    q.push(st),dis[st]=0;
    while(!q.empty()){
        int u=q.front();q.pop();
        vis[u]=0;
        for(int i=last[u];~i;i=nxt[i]){
            int v=to[i];
            if(dis[v]>dis[u]+w[i]){
                dis[v]=dis[u]+w[i];
                if(!vis[v]) q.push(v),vis[v]=1;
            }
        }
    }
    return ;
}

矩阵

struct matrix{
    int row,col;
    int mp[maxn][maxn]={};
    matrix(int _row=0,int _col=0){
        row=_row,col=_col;
    }
    matrix operator+(const matrix &b) const{
        matrix c=matrix(row,col);
        for(int i=1;i<=row;i++){
            for(int j=1;j<=col;j++) c.mp[i][j]=mp[i][j]+b.mp[i][j];
        }
        return c;
    }
    matrix operator-(const matrix &b) const{
        matrix c=matrix(row,col);
        for(int i=1;i<row;i++){
            for(int j=1;j<=col;j++) c.mp[i][j]=mp[i][j]-b.mp[i][j];
        }
        return c;
    }
    matrix operator*(const matrix &b) const{
        matrix c=matrix(row,b.col);
        for(int i=1;i<=row;i++){
            for(int k=1;k<=col;k++){
                if(!mp[i][k]) continue;
                for(int j=1;j<=b.col;j++) c.mp[i][j]+=mp[i][k]*b.mp[k][j];
            }
        }
        return c;
    }
};

matrix qpow(matrix a,int b){
    matrix c=matrix(a.row,a.col);
    for(int i=1;i<=a.row;i++) c.mp[i][i]=1;
    while(b){
        if(b&1ll) c=c*a;
        a=a*a,b>>=1ll;
    }
    return c;
}

字典树

struct trie{
    int rot,cnt;
    int f[maxn],s[maxn][maxv];
    trie(){
        rot=1,cnt=2;
    }
    void insert(char w[]){
        int len=strlen(w),now=rot;
        for(int i=0;i<len;i++){
            if(!s[now][w[i]-'a']) s[now][w[i]-'a']=++cnt;
            now=s[now][w[i]-'a']; 
        }
        f[now]++;
        return ;
    }
    void delet(char w[]){
        int len=strlen(w),now=rot;
        for(int i=0;i<len;i++){
            if(!s[now][w[i]-'a']) s[now][w[i]-'a']=++cnt;
            now=s[now][w[i]-'a']; 
        }
        f[now]=max(f[now]-1,0);
        return ;
    }
    bool query(char w[]){
        int len=strlen(w),now=rot;
        for(int i=0;i<len;i++){
            if(!s[now][w[i]-'a']) return 0;
            now=s[now][w[i]-'a']; 
        }
        return f[now];
    }
};

\text{Splay}

void link(int u,bool d,int v){
    s[u][d]=v,f[v]=u;
    return ;
}

void pushup(int u){
    siz[u]=1;
    if(s[u][0]) siz[u]+=siz[s[u][0]];
    if(s[u][1]) siz[u]+=siz[s[u][1]];
    return ;
}

void rotation(int now){
    int u=f[now],v=f[u];
    bool d=s[u][0]==now;
    link(u,d^1,s[now][d]),link(now,d,u),link(v,s[v][1]==u,now);
    pushup(u),pushup(now);
    return ;
}

void splay(int now,int top){
    while(f[now]!=top){
        int u=f[now],v=f[u];
        if(v!=top){
            if((s[u][0]==now)==(s[v][0]==u)) rotation(u); 
            else rotation(now); 
        }
        rotation(now);
    }
    if(top==0) root=now;
}

int find(int val){
    int now=root,d;
    while(now){
        if(val==data[now]){
            splay(now,0);
            return now;
        }
        d=val>data[now];
        if(s[now][d]) now=s[now][d];
        else break;
    }
    return -1;
}

int merge(int l,int r){
    if(!l||!r) return l+r;
    while(s[l][1]) l=s[l][1];
    splay(l,0),link(l,1,r),pushup(l);
    return l;
}

void insert(int val){
    int now=root,d;
    while(now){
        d=val>data[now];
        if(s[now][d]) now=s[now][d];
        else break;
    }
    data[++cnt]=val,siz[cnt]=1;
    if(now) link(now,d,cnt),pushup(now);
    splay(cnt,0);
    return ;
}

void delet(int val){
    int now=find(val);
    if(now==-1) return ;
    splay(now,0);
    f[s[now][0]]=f[s[now][1]]=0;
    root=merge(s[now][0],s[now][1]);
    return ;
}

int count(int val){
    int now=root,t=0;
    while(now){
        if(data[now]<val) t+=siz[s[now][0]]+1,now=s[now][1];
        else now=s[now][0];
    }
    return t;
}

int _rank(int val){
    return count(val)+1;
}

int kth(int val){
    int now=root,t;
    while(now){
        t=siz[s[now][0]]+1;
        if(val==t) break;
        if(val>t) val-=t,now=s[now][1];
        else now=s[now][0];
    }
    if(now) splay(now,0);
    return now;
}