(长期更新)OI常用模板

代码很简单的模板就不收录了。

DFT 离散傅立叶变换

void dft(pdd *a,int l,bool r){
    int i,j=l/2,k;
    for(i=1;i>=1) j^=k;
        j^=k;
    }
    for(i=1;(1<>1);++k){
                pdd v1=a[j+k],v2=a[j+k+(cl>>1)]*cur;
                a[j+k]=v1+v2;
                a[j+k+(cl>>1)]=v1-v2;
                cur=cur*w;
            }
        }
    }
}

hint: 参数 bool r 表示是否在进行逆向的 DFT(即是否是在插值)

hint2: pdd 是手写的 complex 类

NTT 快速数论变换

const LL MOD=998244353,G=3;
const LL MOD2=1004535809,G2=3;
const LL MOD3=65537,G3=3;
void ntt(int *a,int l,bool r){
    int i,j=l/2,k;
    for(i=1;i>=1) j^=k;
        j^=k;
    }
    for(i=1;(1<>1);++k){
                int v1=a[j+k],v2=(LL)a[j+k+(cl>>1)]*(LL)cur%MOD;
                a[j+k]=v1+v2;
                a[j+k+(cl>>1)]=v1-v2;
                if(a[j+k]>=MOD) a[j+k]-=MOD;
                if(a[j+k+(cl>>1)]<0) a[j+k+(cl>>1)]+=MOD;
                cur=(LL)cur*(LL)w%(LL)MOD;
            }
        }
    }
}

hint: powM(A,B)=\(A^B \bmod MOD\)

后缀自动机与广义后缀自动机

不同于某些无脑写法,这里的GSAM保证不存在等价结点。

struct node{
    node *nx[ALPHABET],*fa;
    int mxl;
    void init(){
        mxl=0;
        fa=0;
        memset(nx,0,sizeof(nx));
    }
}*last,*root;
void extend(int v){// for SAM
    node *p=last,*np=new node;
    np->init();
    np->mxl=p->mxl+1;
    for(;p && !p->nx[v];p=p->fa) p->nx[v]=np;
    if(!p) np->fa=root;
    else{
        node *q=p->nx[v];
        if(q->mxl==p->mxl+1){
            np->fa=q;
        }
        else{
            node *nq=new node;
            nq->init();
            nq->mxl=p->mxl+1;
            memcpy(nq->nx,q->nx,sizeof(q->nx));
            nq->fa=q->fa;
            q->fa=np->fa=nq;
            for(;p && p->nx[v]==q;p=p->fa) p->nx[v]=nq;
        }
    }
    last=np;
}
void extend(int c){// for GSAM
    node *p=last;
    if(p->nx[c]){
        if(p->nx[c]->mxl==p->mxl+1)
            last=p->nx[c];
        else{
            node *q=p->nx[c],*nq=new node;
            nq->init();
            memcpy(nq->nx,q->nx,sizeof(q->nx));
            nq->mxl=p->mxl+1;
            nq->fa=q->fa;
            q->fa=nq;
            last=nq;
            for(;p && p->nx[c]==q;p=p->fa)
                p->nx[c]=nq;
        }
        return;
    }
    node *np=new node;
    np->init();
    np->mxl=p->mxl+1;
    for(;p && !(p->nx[c]);p=p->fa)
        p->nx[c]=np;
    if(!p)
        np->fa=root;
    else{
        node *q=p->nx[c];
        if(q->mxl==p->mxl+1)
            np->fa=q;
        else{
            node *nq=new node;
            nq->mxl=p->mxl+1;
            memcpy(nq->nx,q->nx,sizeof(q->nx));
            nq->fa=q->fa;
            q->fa=np->fa=nq;
            for(;p && p->nx[c]==q;p=p->fa)
                p->nx[c]=nq;
        }
    }
    last=np;
}

SA&LCP 后缀数组全家桶

void bsort(){
    int i;
    memset(cnt,0,sizeof(cnt));
    for(i=0;i=0;--i) tmp[--cnt[vy[i]]]=i;
    memset(cnt,0,sizeof(cnt));
    for(i=0;i=0;--i) ls[--cnt[rk[tmp[i]]]]=tmp[i];
    memset(tmp,0,sizeof(tmp));
}
void getsa(){
    int i,j,cv;
    memset(rk,0,sizeof(rk));
    memset(vy,0,sizeof(vy));
    for(i=0;i>1)];
        }
        bsort();
        cv=1;
        for(j=0;j

hint: vy=value_Y 意为第二排序准则

hint2: rk=rank lv=last_value ls=list

hint3: 可能是因为我的写法太鬼畜了,这段代码里改动几乎任何一处看似无关紧要的细节都会GG……别问我为什么

点分治

void getcen(int ver,int fa,int ts){
    int i,j,k,cv=ts-sz[ver];
    for(i=0;i<(int)adj[ver].size();++i){
        if(adj[ver][i]!=fa && !del[adj[ver][i]]){
            UMAX(cv,sz[adj[ver][i]]);
            getcen(adj[ver][i],ver,ts);
        }
    }
    UMIN(cur,mpr(cv,ver));
}
void deepin(int ver,int fa){
    int i,j,k;
    sz[ver]=1;
    for(i=0;i<(int)adj[ver].size();++i){
        if(!del[adj[ver][i]] && adj[ver][i]!=fa){
            deepin(adj[ver][i],ver);
            sz[ver]+=sz[adj[ver][i]];
        }
    }
}
int centroid(int ver){
    cur=mpr(iinf,-1);
    getcen(ver,-1,sz[ver]);
    return cur.second;
}
void solve(int ver){
    del[ver]=1;
    int i,j,k;
    for(i=0;i<(int)adj[ver].size();++i){
        if(!del[adj[ver][i]]){
            deepin(adj[ver][i],ver);
        }
    }
    for(i=0;i<(int)adj[ver].size();++i){
        if(!del[adj[ver][i]]){
            solve(centroid(adj[ver][i]));
        }
    }
}
solve(0);

hint: cv=current_value sz=size

线性基

struct basis{
    int arr[35],got[35];
    void init(){
        memset(arr,0,sizeof(arr));
        memset(got,0,sizeof(got));
    }
    void insert(int v){
        int i,j;
        for(i=0;i<31;++i){
            if(v&(1<=0;--i){
            if(v&(1<=0;--j) if(v&(1<

线段树合并与分裂

#define SZ(X) ((X)?((X)->cnt):0)
struct node{
    node *lc,*rc;
    int cnt;
    void init(){lc=rc=0;cnt=0;}
    void upd(){cnt=SZ(lc)+SZ(rc);}
    bool leaf(){return (!lc && !rc);}
    
    void ins(int d,int l=0,int r=U){
        ++cnt;
        if(l==r) return;
        int M=((l+r)>>1);
        if(d<=M){
            if(!lc){
                lc=new node;
                lc->init();
            }
            lc->ins(d,l,M);
        }
        else{
            if(!rc){
                rc=new node;
                rc->init();
            }
            rc->ins(d,M+1,r);
        }
    }
    int loc(int id,int l=0,int r=U){
        if(l==r) return l;
        int M=((l+r)>>1);
        if(idloc(id,l,M);
        return rc->loc(id-SZ(lc),M+1,r);
    }
};
node *merge(node *A,node *B){
    if(!A || !B) return (A?A:B);
    if(A->leaf() && B->leaf()){
        A->cnt+=B->cnt;
        delete B;
        return A;
    }
    node *lc=merge(A->lc,B->lc),*rc=merge(A->rc,B->rc);
    A->lc=lc;
    A->rc=rc;
    A->cnt=SZ(lc)+SZ(rc);
    delete B;
    return A;
}
void split(node *S,int sz,node *&A,node *&B){
    if(!S) A=B=0;
    else if(S->leaf()){
        A=S;
        B=new node;
        B->init();
        B->cnt=S->cnt-sz;
        // valuation for B->cnt must be before A->cnt, as A==S is possible.
        A->cnt=sz;
    }
    else if(SZ(S->lc)init();
        split(A->rc,sz-SZ(S->lc),A->rc,B->rc);
        A->upd();B->upd();
    }
    else{
        B=S;
        A=new node;
        A->init();
        split(B->lc,sz,A->lc,B->lc);
        A->upd();B->upd();
    }
}

网络流退流(Ford-Fulkerson版本)

namespace flows{
    const int S=202,T=203;
    vector < pii > adj[205];
    int id[205][205],flow;
    bool vis[205];
    void init(){
        memset(id,-1,sizeof(id));
        int i;
        for(i=0;i<205;++i) adj[i].clear();
        flow=0;
    }
    void addedge(int u,int v,int f){
        id[u][v]=(int)adj[u].size();
        adj[u].push_back(mpr(v,f));
        id[v][u]=(int)adj[v].size();
        adj[v].push_back(mpr(u,0));
    }
    int dfs(int ver,int cur,int tar=T){
        int i,j,k;
        if(ver==tar || !cur) return cur;
        vis[ver]=1;
        for(i=0;i<(int)adj[ver].size();++i){
            pii &E=adj[ver][i];
            if(E.second && !vis[E.first]){
                int R=id[E.first][ver],
                    F=dfs(E.first,MIN(cur,E.second),tar);
                if(F){
                    E.second-=F;
                    adj[E.first][R].second+=F;
                    return F;
                }
            }
        }
        return 0;
    }
    void set(){
        memset(vis,0,sizeof(vis));
    }
    void push(){
        while(1){
            set();
            int F=dfs(S,iinf);
            if(F) flow+=F; else break;
        }
    }
    void edit(int u,int v,int w){
        int d=id[u][v],rd=id[v][u],
            f=adj[u][d].second+adj[v][rd].second;
        if(adj[v][rd].second<=w){
            adj[u][d].second+=w-f;
        }
        else{
            int pf=adj[v][rd].second;
            adj[u][d].second=adj[v][rd].second=0;
            while(pf>w){
                set();
                int dlt=dfs(u,pf-w,v);
                pf-=dlt;
                if(!dlt) break;
            }
            set();
            dfs(T,pf-w,v);
            set();
            dfs(u,pf-w,S);
            flow-=pf-w;
            adj[v][rd].second=w;
        }
    }
};

LCT基本款
(之后我大概会在新文章里写一下维护子树信息的LCT?)咕咕咕

namespace LCT{
    struct node{
        node *s[2],*fa;
        int sz,pfa,rev;
        void init(){
            s[0]=s[1]=fa=0;
            pfa=-1;
            rev=0;
            sz=1;
        }
        int pos(){
            return fa->s[1]==this;
        }
        void push(){
            if(rev){
                swap(s[0],s[1]);
                if(s[0]) s[0]->rev^=1;
                if(s[1]) s[1]->rev^=1;
                rev=0;
            }
        }
        void pull(){
            sz=SZ(s[0])+SZ(s[1])+1;
        }
        void rotate(){
            if(fa){
                node *F=fa;
                int ps=pos();
                fa=F->fa;
                if(fa) fa->s[F->pos()]=this;
                pfa=F->pfa;
                F->pfa=-1;
                F->fa=this;
                if(ps){
                    F->s[1]=s[0];
                    if(s[0]) s[0]->fa=F;
                    s[0]=F;
                }
                else{
                    F->s[0]=s[1];
                    if(s[1]) s[1]->fa=F;
                    s[1]=F;
                }
                F->pull();
                pull();
            }
        }
        void splay(node *tar=0){
            while(fa!=tar){
                if(fa->fa) fa->fa->push();
                fa->push();
                push();
                
                if(fa->fa==tar){
                    rotate();
                }
                else if(pos()==fa->pos()){
                    fa->rotate();rotate();
                }
                else{
                    rotate();rotate();
                }
            }
        }
    }*vers[200005];
    void init(){
        int i;
        for(i=0;i<=n;++i){
            vers[i]=new node;
            vers[i]->init();
        }
    }
    void expose(int u){
        vers[u]->splay();
        vers[u]->push();
        if(vers[u]->s[1]){
            vers[u]->s[1]->pfa=u;
            vers[u]->s[1]->fa=0;
            vers[u]->s[1]=0;
            vers[u]->pull();
        }
    }
    bool extend(int u){
        vers[u]->splay();
        int &v=vers[u]->pfa;
        if(v!=-1){
            expose(v);
            vers[v]->s[1]=vers[u];
            vers[u]->fa=vers[v];
            vers[v]->pull();
            v=-1;
            return 1;
        }
        return 0;
    }
    void access(int u){
        expose(u);
        while(extend(u));
    }
    void setroot(int u){
        access(u);
        vers[u]->rev^=1;
    }
    void link(int u,int v){
        setroot(u);
        vers[u]->pfa=v;
    }
    void cut(int u,int v){
        setroot(u);
        access(v);
        vers[v]->push();
        vers[v]->s[0]->fa=0;
        vers[v]->s[0]=0;
        vers[v]->pull();
    }
};

可持久化Treap
\(mn\)\(mx\),和\(k\)是节点内维护的一些数据,与模板无关。

#define SZ(x) ((x)?((x)->sz):0)
struct node{
    node *s[2];
    int mn,mx,sz,k,fix;
    void init(int K){
        sz=1;
        fix=rand();
        k=mn=mx=K;
        s[0]=s[1]=0;
    }
    void pull(){
        sz=SZ(s[0])+SZ(s[1])+1;
        mn=mx=k;
        if(s[0]){
            mn=min(mn,s[0]->mn);
            mx=max(mx,s[0]->mx);
        }
        if(s[1]){
            mn=min(mn,s[1]->mn);
            mx=max(mx,s[1]->mx);
        }
    }
};
void copy(node *S,node *&T){
    if(!S) T=0;
    T=new node;
    *T=*S;
}
void merge(node *&T,node *A,node *B){
    if(!A || !B){
        copy((A?A:B),T);
        return;
    }
    if(A->fixfix){
        copy(A,T);
        merge(T->s[1],A->s[1],B);
    }
    else{
        copy(B,T);
        merge(T->s[0],A,B->s[0]);
    }
    T->pull();
}
void splitkey(int K,node *S,node *&A,node *&B){
    if(!S){
        A=B=0;
        return;
    }
    if(S->ks[1],A->s[1],B);
        A->pull();
    }
    else{
        copy(S,B);
        splitkey(K,S->s[0],A,B->s[0]);
        B->pull();
    }
}

动态直线下凸壳
支持\(\mathrm{O}(\log n)\)插入直线,\(\mathrm{O}(\log n)\)单点查询最大值。
常数中等。正确性应该可靠。

const double MOGIC=-1926.0817,eps=1e-8;
struct Line{
    LL K,B;
    mutable double T;
    void set(LL k,LL b,double t=MOGIC){
        K=k;B=b;T=t;
    }
    bool operator <(Line Y) const{
        if(T==MOGIC||Y.T==MOGIC) return (K!=Y.K?KY.B);
        return T lines;
    void ins(Line L){
        L.T=MOGIC;
        if(lines.empty()){
            L.T=(double)-linf;
            lines.insert(L);
        }
        else{
            set < Line >::iterator it=lines.lower_bound(L),lt=it,cr;
            if(it->K==L.K && it->B==L.B) return;
            if(it==lines.begin()){
                L.T=(double)-linf;
                if(it->K==L.K) lines.erase(lines.begin());
                if(!lines.empty()){
                    it=lines.begin();
                    it->T=intersect(L,*it);
                    while((++it)!=lines.end() && lines.begin()->T>it->T+eps){
                        lines.erase(lines.begin());
                        it->T=intersect(L,*it);
                    }
                }
                lines.insert(L);
                return;
            }
            if((--lt)->K==L.K) return;
            if(it==lines.end()){
                L.T=intersect(L,*(lines.rbegin()));
                while(lines.rbegin()->T>L.T-eps){
                    lt=lines.end();
                    lines.erase(--lt);
                    L.T=intersect(L,*(lines.rbegin()));
                }
                lines.insert(L);
                return;
            }
            while(1){
                cr=it++;
                if(it==lines.end()) break;
                if(intersect(*lt,L)>intersect(*lt,*cr)-eps || intersect(*it,L)K==L.K){
                lines.erase(cr);
                while(lt!=lines.begin()){
                    cr=lt--;
                    L.T=intersect(*cr,L);
                    if(L.TT+eps) lines.erase(cr); else break;
                }
                L.T=intersect(*lines.rbegin(),L);
                lines.insert(L);
                return;
            }
            --it;
            while(1){
                if(lt==lines.begin()) break;
                cr=lt--;
                if(intersect(*it,L)intersect(*lt,*cr)+eps){
                    lt=cr;
                    break;
                }
                lines.erase(cr);
            }
            L.T=intersect(*lt,L);
            if(L.TT=intersect(*it,L);
                lines.insert(L);
            }
        }
    }
    LL qry(LL D){
        tmp.set(0,0,D);
        set < Line > ::iterator it=lines.lower_bound(tmp);
        return eval(D,*(--it));
    }
};

KM算法
二分图最大权匹配,见UOJ #80

namespace KM{
    int n[2],w[505][505];
    int matchL[505],matchR[505],pred[505];
    int labL[505],labR[505],slk[505];
    bool inS[505];
    void init(int N){
        n[0]=n[1]=N;
        memset(w,0,sizeof(w));
        memset(matchL,-1,sizeof(matchL));
        memset(matchR,-1,sizeof(matchR));
    }
    LL solve(){
        int i,j,k;
        memset(labR,0,sizeof(labR));
        for(i=0;i0) UMIN(dec,slk[j]);
                    }
                    if(dec>0){
                        for(j=0;j

带花树算法
一般图最大匹配,见UOJ #79

namespace Blossom{
    int n,sta[505],fa[505];
    int pred[505],match[505];
    int tick,mark[505];
    int pl,pr,que[1005];
    vector < int > adj[505];
    void init(int N){
        n=N;
        int i;
        for(i=0;i

ZKW费用流
来源

namespace ZKW{// min cost max flow
    const int V=440, E=V*2, maxint=0x3F3F3F3F;
    struct etype{
        int t, c, u;
        etype *next, *pair;
        etype() {}
        etype(int T, int C, int U, etype* N): t(T), c(C), u(U), next(N) {}
        void* operator new(unsigned long long, void* p){return p;}
    }*e[V], Te[E+E], *Pe;
    int S, T, n, piS, cost;
    bool v[V];
    void init(int N){
        n=N;S=0;T=1;
        Pe=Te;
        memset(e,0,sizeof(etype*)*(n+2));
        cost=piS=0;
    }
    void addedge(int s, int t, int c, int u){
        e[s] = new(Pe++) etype(t, +c, u, e[s]);
        e[t] = new(Pe++) etype(s, -c, 0, e[t]);
        e[s]->pair = e[t];
        e[t]->pair = e[s];
    }
    int aug(int no, int m){
        if (no == T) return cost += piS * m, m;
        v[no] = true;
        int l = m;
        for (etype *i = e[no]; i; i = i->next)
            if (i->u && !i->c && !v[i->t]){
                int d = aug(i->t, l < i->u ? l : i->u);
                i->u -= d, i->pair->u += d, l -= d;
                if (!l) return m;
            }
        return m - l;
    }
    bool modlabel(){
        static int d[V]; memset(d, 0x3F, sizeof(d)); d[T] = 0;
        static deque Q; Q.push_back(T);
        while(Q.size()){
            int dt, no = Q.front(); Q.pop_front();
            for(etype *i = e[no]; i; i = i->next)
                if(i->pair->u && (dt = d[no] - i->c) < d[i->t])
                    (d[i->t] = dt) <= d[Q.size() ? Q.front() : 0]
                        ? Q.push_front(i->t) : Q.push_back(i->t);
        }
        for(int i = 0; i < n; ++i)
            for(etype *j = e[i]; j; j = j->next)
                j->c += d[j->t] - d[i];
        piS += d[S];
        return d[S] < maxint;
    }
    void getcost(){
        while(modlabel())
            do memset(v, 0, sizeof(int)*(n+2));
            while(aug(S, maxint));
    }
}

替罪羊式的K-D Tree
题目链接
在平面上支持插入点、查询曼哈顿最近点。

bool dim;
bool cmp(pii A,pii B){
    return (dim?A.SC:A.FS)<(dim?B.SC:B.FS);
}
inline int dis(pii A,pii B){
    return ABS(A.FS-B.FS)+ABS(A.SC-B.SC);
}
int ans,cnt;
pii ele[600005];
#define SZ(x) ((x)?((x)->sz):0)
struct node{
    node *s[2];
    pii cen;
    int dep,xl,xr,yl,yr,sz;// coordinates of rectangle
    bool bad(){
        return MAX(SZ(s[0]),SZ(s[1]))*4>sz*3+20;
    }
    void init(){
        s[0]=s[1]=0;
        dep=sz=0;
    }
    void extend(int d){
        s[d]=new node;
        s[d]->init();
        s[d]->xl=xl;s[d]->xr=xr;
        s[d]->yl=yl;s[d]->yr=yr;
        s[d]->dep=dep+1;
        if(!d){
            if(dep&1) s[0]->yr=cen.SC;
            else      s[0]->xr=cen.FS;
        }
        else{
            if(dep&1) s[1]->yl=cen.SC;
            else      s[1]->xl=cen.FS;
        }
    }
    void build(pii *L,pii *R){
        sz=R-L+1;
        int M=sz/2,i,j,k;
        dim=(dep&1);
        nth_element(L,L+M,R+1,cmp);
        cen=*(L+M);
        if(M){
            extend(0);
            s[0]->build(L,L+M-1);
        }
        if(L+Mbuild(L+M+1,R);
        }
    }
    inline int sdis(int L,int R,int X){
        return ((X>=L && X<=R)?0:MIN(ABS(X-L),ABS(X-R)));
    }
    int rdis(pii P){
        return sdis(xl,xr,P.FS)+sdis(yl,yr,P.SC);
    }
    void query(pii P){
        UMIN(ans,dis(P,cen));
        if(rdis(P)>=ans) return;
        node *A=s[0],*B=s[1];
        if(B && (!A || A->rdis(P)>B->rdis(P)))
            swap(A,B);
        if(A) A->query(P);
        if(B) B->query(P);
    }
    void ins(pii P,node *&ls){
        ++sz;
        dim=(dep&1);
        int d=cmp(cen,P);
        if(!s[d]){
            extend(d);
            s[d]->cen=P;
            s[d]->sz=1;
            ls=0;
        }
        else s[d]->ins(P,ls);
        if(bad()) ls=this;
    }
    void travel(){
        if(s[0]) s[0]->travel();
        ele[cnt++]=cen;
        if(s[1]) s[1]->travel();
    }
    void del(){
        if(s[0]){
            s[0]->del();
            delete s[0];
            s[0]=0;
        }
        if(s[1]){
            s[1]->del();
            delete s[1];
            s[1]=0;
        }
    }
}*root;
void rebuild(node *p){
    cnt=0;
    p->travel();
    p->del();
    p->build(ele,ele+cnt-1);
}
void insert(pii P){
    node *r=0;
    root->ins(P,r);
    if(r) rebuild(r);
}
int query(pii P){
    ans=iinf;
    root->query(P);
    return ans;
}

广义圆方树建树
对于点双建立方点。

int en[200005],low[200005],tick,cnt;// initially cnt set to |V|, en set to -1
int sz,stk[200005],fa[400005];
vector < int > son[400005],adj[200005];
void setfa(int s,int f){
    fa[s]=f;
    son[f].push_back(s);
}
void tarjan(int v,int f){
    int i,j,k;
    stk[sz++]=v;
    en[v]=low[v]=tick++;
    for(i=0;i<(int)adj[v].size();++i){
        int u=adj[v][i];
        if(u!=f){
            if(en[u]==-1){
                tarjan(u,v);
                UMIN(low[v],low[u]);
                if(low[u]==en[v]){
                    int cen=cnt++;
                    setfa(cen,v);
                    while(sz && en[stk[sz-1]]>=en[u]){
                        setfa(stk[sz-1],cen);
                        --sz;
                    }
                }
                else if(low[u]==en[u]){
                    int cen=cnt++;
                    setfa(u,cen);
                    setfa(cen,v);
                    assert(sz && stk[sz-1]==u);
                    --sz;
                }
            }
            else UMIN(low[v],en[u]);
        }
    }
}

转载于:https://www.cnblogs.com/turboboost/p/templates.html

你可能感兴趣的:((长期更新)OI常用模板)