ACM模板(个人代码集整理)(博客停止更新,内附github链接,会在github继续更新)

这篇博客整理了ACM竞赛中常用的算法模板和数据结构,包括DFS找环、Tarjan算法、树链剖分、最大流、最小费用最大流、线段树等,并提供了github链接以获取最新更新。
摘要由CSDN通过智能技术生成

为方便区域赛打印pdf模板,所有代码已经搬家到了github中。

目录:

SAM(*)

SA(*)

PAM(*)

树链剖分(*)

01Trie(*)

ACAM(*)

KMP(*)

LCA(*)

主席树(*)

点分治(*)

kd-Tree(*)

斜率优化DP

最大流Dicnic(*)

最小费用最大流(SPFA)(*)

线段树(*)

dfs靠谱找环

靠谱找凸包(*)

tarjan缩点+点双连通(寻割)+边双连通(寻桥)

虚树(*)

圆方树(*)

FFT(*)

 

SAM+LCT在线动态维护parent树:

#include<bits/stdc++.h>
#define N 1200005
#define inf 1000000007
using namespace std;
int mask;char s[3000005];
int Q;
string chars;
void gets(int mask){
    scanf("%s",s);chars=s;
    for(int j=0;j<chars.length();j++){
        mask=(mask*131+j)%chars.length();
        char t=chars[j];
        chars[j]=chars[mask];
        chars[mask]=t;
    }
}
struct Link_Cut_Tree{
    int top,fa[N],c[N][2],val[N],tag[N],q[N];
    inline void add(int x,int y){if(x)tag[x]+=y,val[x]+=y;}
    inline void pushdown(int x){
        int l=c[x][0],r=c[x][1];
        if(tag[x]){
            add(l,tag[x]);add(r,tag[x]);
            tag[x]=0;
        }
    }
    inline bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
    inline void rotate(int x){
        int y=fa[x],z=fa[y],l,r;
        if(c[y][0]==x)l=0;else l=1;r=l^1;
        if(!isroot(y)){if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;}
        fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
        c[y][l]=c[x][r];c[x][r]=y;
    }
    inline void splay(int x){
        int top=1;q[top]=x;
        for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i];
        for(int i=top;i;i--)pushdown(q[i]);
        while(!isroot(x)){
            int y=fa[x],z=fa[y];
            if(!isroot(y)){
                if((c[z][0]==y)^(c[y][0]==x))rotate(x);
                else rotate(y);
            }rotate(x);
        }
    }
    void access(int x){for(int t=0;x;t=x,x=fa[x])splay(x),c[x][1]=t;}
    inline void link(int x,int y){fa[x]=y;access(y);splay(y);add(y,val[x]);}
    inline void cut(int x){
        access(x);splay(x);add(c[x][0],-val[x]);
        fa[c[x][0]]=0;c[x][0]=0;
    }    
}T;
struct Suffix_AutoMaton{
    int l[N],fa[N],ch[N][26];
    int cnt,last;
    Suffix_AutoMaton(){cnt=1;last=1;}
    void ins(int c){
        int p=last,np=++cnt;last=np;T.val[np]=1;l[np]=l[p]+1;
        for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
        if(!p)fa[np]=1,T.link(np,1);
        else{
            int q=ch[p][c];
            if(l[p]+1==l[q])fa[np]=q,T.link(np,q);
            else{
                int nq=++cnt;l[nq]=l[p]+1;
                memcpy(ch[nq],ch[q],sizeof(ch[q]));
                fa[nq]=fa[q];T.link(nq,fa[q]);
                fa[np]=fa[q]=nq;
                T.cut(q);T.link(q,nq);T.link(np,nq);
                for(;ch[p][c]==q;p=fa[p])ch[p][c]=nq;
            }
        }
    }
    void build(){
        scanf("%s",s);int len=strlen(s);
        for(int i=0;i<len;i++)ins(s[i]-'A');
    }
    int query(){
        gets(mask);
        int p=1;int len=chars.length();
        for(int i=0;i<len;i++)if(!(p=ch[p][chars[i]-'A']))return 0;
        T.splay(p);
        return T.val[p];
    }
    void add(){
        gets(mask);int len=chars.length();
        for(int i=0;i<len;i++)ins(chars[i]-'A');
    }
}sam;
int main(){
    scanf("%d",&Q);sam.build();
    while(Q--){
        scanf("%s",s);
        if(*s=='A')sam.add();
        else{
            int ans=sam.query();
            printf("%d\n",ans);
            mask^=ans;
        }
    }
    return 0;
}

 

SAM动态求 出现至少k次本质不同子串个数:

 

#include<bits/stdc++.h>  
using namespace std;  
const int maxn = 25e4+1000;  
char s[maxn];  int len,k,n,m;  char temp[5];  
struct SAM{  
    int last,cnt,nxt[maxn*2][26],fa[maxn*2],l[maxn*2],num[maxn*2];  
    int ans;  
    void init(){  
        last = cnt=1;  
        memset(nxt[1],0,sizeof nxt[1]);  
        fa[1]=l[1]=num[1]=0;  
        ans=0;  
    }  
    int inline newnode(){  
        cnt++;  
        memset(nxt[cnt],0,sizeof nxt[cnt]);  
        fa[cnt]=l[cnt]=num[cnt]=0;  
        return cnt;  
    }  
    void add(int c){  
        int p = last;    int np = newnode();    
        last = np;    l[np] =l[p]+1;    
        while (p&&!nxt[p][c]){    
            nxt[p][c] = np;    
            p = fa[p];    
        }    
        if (!p){ fa[np] =1;}
        else{    
            int q = nxt[p][c];    
            if (l[q]==l[p]+1){fa[np] =q;}
            else{    
                int nq = newnode();    
                memcpy(nxt[nq],nxt[q],sizeof nxt[q]);    
                fa[nq] =fa[q]; num[nq] = num[q];  
                l[nq] = l[p]+1; fa[np] =fa[q] =nq;    
                while (nxt[p][c]==q){    
                    nxt[p][c]=nq;    
                    p = fa[p];    
                }    
            }    
        }  
        int temp = last;  
        while (temp){  
            if (num[temp]>=k){  break;  }  
            num[temp]++;  
            if (num[temp]==k){  
                ans+=l[temp]-l[fa[temp]];  
            }  
            temp = fa[temp];  
        }    
    }  
}sam;  
int main(){  
    while (scanf("%d%d%d",&n,&m,&k)!=EOF){  
        scanf("%s",s);  
        len = strlen(s);  sam.init();  
        for (int i=0;i<len;i++){  sam.add(s[i]-'a');  }  
        while (m--){  
            int flag;  
            scanf("%d",&flag);  
            if (flag==1){  
                scanf("%s",temp);  
                sam.add(temp[0]-'a');  
            }else{  
                printf("%d\n",sam.ans);  
            }  
        }  
    }  
    return 0;  
}  

SAM 字典序第k小串

#include<bits/stdc++.h>  
using namespace std;  
const int maxn = 9e4+1000;  
int len;  char s[maxn];  
int cntA[maxn];  vector<char> ans;  
struct SAM{  
    int last,cnt,nxt[maxn*2][26],fa[maxn*2],l[maxn*2];  
    int rk[maxn*2],num[maxn*2];  
    void init(){  
        last = cnt=1;  
        memset(nxt[1],0,sizeof nxt[1]);  
        fa[1]=l[1] =0;  
    }  
    void add(int c){  
        int p = last;  int np = ++cnt;  
        last = np;  l[np] =l[p]+1;  
        while (p&&!nxt[p][c]){  
            nxt[p][c] = np;  
            p = fa[p];  
        }  
        if (!p){  fa[np] =1;}
        else{  
            int q = nxt[p][c];  
            if (l[q]==l[p]+1){  fa[np] =q; }
            else{  
                int nq = ++cnt;  
                memcpy(nxt[nq],nxt[q],sizeof nxt[q]);  
                fa[nq] =fa[q];  l[nq] = l[p]+1;  
                fa[np] =fa[q] =nq;  
                while (nxt[p][c]==q){  
                    nxt[p][c]=nq;  
                    p = fa[p];  
                }  
            }  
        }  
    }  
    void build (){  
        for (int i=1;i<=cnt;i++){  
            cntA[l[i]]++;  
        }  
        for (int i=1;i<maxn-5;i++){  
            cntA[i]+=cntA[i-1];  
        }  
        for (int i=1;i<=cnt;i++){  
            rk[cntA[l[i]]--] =i;  
        }  
        for (int i=1;i<=cnt;i++){  
            num[i]=1;  
        }  
        for (int i=cnt;i>=1;i--){  
            int x = rk[i];  
            for (int i=0;i<26;i++){  
                if (nxt[x][i]){  
                    num[x]+=num[nxt[x][i]];  
                }  
            }  
        }  
        num[0]=0;  
    }  
    inline void print(){  
        for (char t:ans){  
            printf("%c",t);  
        }  
        printf("\n");  
    }  
    void query(int K){  
        ans.clear();  
        int now=1; int sum=0;  
        while (true){  
            if (sum==K){  
                print();  
                return ;  
            }  
            int c=0;  
            int last =0;  
            while (sum<K){  
                sum+=num[nxt[now][c]];  
                c++;  
                assert(c<27);  
            }  
            c--;  
            sum-=num[nxt[now][c]];  
            now = nxt[now][c];  
            ans.push_back('a'+c);  
            sum++;  
        }  
    }  
}sam;  
int main(){  
    int Q;  
    scanf("%s%d",s,&Q);  
    sam.init();  int le = strlen(s);  
    for (int i=0;i<le;i++){  
        sam.add(s[i]-'a');  
    }  
    sam.build();  
    while (Q--){  
        int x;  
        scanf("%d",&x);  
        sam.query(x);  
    }  
    return 0;  
}  

 

SA:

 

SA+Manacher求本质不同回文串个数

#include<bits/stdc++.h>  
using namespace std;  
#define rank rk  
const int MAX = 2e5+10000;  
char ch[MAX];  
int cntA[MAX],cntB[MAX],A[MAX],B[MAX],tsa[MAX],rank[MAX],SA[MAX],lc[MAX],h[MAX];  
int n,t;  int Cas =1;   
void init(){  
    memset(ch,0,sizeof ch);  
    ch[0]='z'+1;  
}  
void input(){  
    scanf("%s",ch+1);  
    n =  strlen(ch+1);  
    ch[n*2+1]='#';  
    for (int i=n;i>=1;i--){  
        ch[i*2] = ch[i];  
        ch[i*2-1] ='#';  
    }  
    n = n*2+1;  
    ch[n+1]='\0';  
}  
void get_SA(){  
    for (int i=0;i<=10000;i++) cntA[i]=0;  
    for (int i=1;i<=n;i++) cntA[ch[i]]++;  
    for (int i=1;i<=10000;i++) cntA[i]+=cntA[i-1];  
    for (int i=n;i>=1;i--) SA[cntA[ch[i]]--] =i;  
    rank[SA[1]]=1;  
    for (int i=2;i<=n;i++){  
        rank[SA[i]]=rank[SA[i-1]];  
        if (ch[SA[i]]!=ch[SA[i-1]]) rank[SA[i]]++;  
    }  
    for (int step = 1;rank[SA[n]]<n;step<<=1){  
        for (int i=0;i<=n;i++)cntA[i]=cntB[i]=0;  
        for (int i=1;i<=n;i++){  
            cntA[A[i]=rank[i]]++;  
            cntB[B[i]=(i+step<=n)?rank[i+step]:0]++;  
        }  
        for (int i=1;i<=n;i++) cntA[i]+=cntA[i-1],cntB[i]+=cntB[i-1];  
        for (int i=n;i>=1;i--) tsa[cntB[B[i]]--] =i;  
        for (int i=n;i>=1;i--) SA[cntA[A[tsa[i]]]--] = tsa[i];  
        rank[SA[1]]=1;  
        for (int i=2;i<=n;i++){  
            rank[SA[i]]=rank[SA[i-1]];  
            if (A[SA[i]]!=A[SA[i-1]]||B[SA[i]]!=B[SA[i-1]]) rank[SA[i]]++;  
        }  
    }  
}  
void get_Height(){  
    for (int i=1,j=0;i<=n;i++){  
        if (j) j--;  
        while (ch[i+j]==ch[SA[rank[i]-1]+j])j++;  
        h[rank[i]]=j;  
    }  
}  
void Manacher(){  
    lc[1]=1;  int k=1;  
    for (int i=2;i<=n;i++){  
        int p = k+lc[k]-1;  
        if (i<=p){  
            lc[i]=min(lc[2*k-i],p-i+1);  
        }else{  lc[i]=1;  }  
        while (ch[i+lc[i]]==ch[i-lc[i]])lc[i]++;  
        if (i+lc[i]>k+lc[k])k=i;  
    }  
}  
void print(){  
    printf("%s\n",ch+1);  
    for (int i=1;i<=n;i++){  
        printf("%s %d\n",ch+SA[i],lc[SA[i]]);  
    }  
}  
void solve(){  
    get_SA();get_Height();Manacher();  
    print();  
    long long res =0;  int cnt=0;  
    for (int i=2;i<=n;i++){  
        cnt = min(cnt,h[i]);  
        res+=max(0,lc[SA[i]]-min(h[i],cnt));  
        if (lc[SA[i]]>cnt){  
            cnt = lc[SA[i]];  
        }  
    }  
    printf("Case #%d: %I64d\n",Cas++,res/2);  
}  
int main(){  
    scanf("%d",&t);  
    while (t--){  
        init();  
        input();  
        solve();  
    }  
    return 0;  
}  

PAM

求公共回文串个数。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+100;
struct PAM{
	int nxt[maxn][26],len[maxn],cnt[maxn],fail[maxn];
	int S[maxn];int last,p,now;
	int newnode(int l){
		memset(nxt[p],0,sizeof nxt[p]);
		cnt[p]=0;len[p]=l;
		return p++;
	}
	void init(){
		p =0;
		newnode(0);newnode(-1);
		last =0;now =0;
		S[now++] =-1;fail[0]=1;
	}
	inline int get_fail(int x){
		int tx =x;
		while (S[now-len[tx]-2]!=S[now-1]) tx = fail[tx];
		return tx;
	} 
	void add(int c){
		S[now++] =c;
		int cur = get_fail(last);
		if (!nxt[cur][c]){
			int tt = newnode(len[cur]+2);
			fail[tt] = nxt[get_fail(fail[cur])][c];
			nxt[cur][c] =tt;
		}
		last = nxt[cur][c];cnt[last]++;
	}
	void count(){
		for (int i=p-1;i>=0;i--){
			cnt[fail[i]]+=cnt[i];
		}
		cnt[0]=cnt[1]=0;
	}

}pam1,pam2;
long long dfs(int u,int v){
	long long res =0;
	for (int i=0;i<26;i++){
		int uu = pam1.nxt[u][i];
		int vv = pam2.nxt[v][i];
		if (uu&&vv){
			res +=1LL*pam1.cnt[uu]*pam2.cnt[vv];
			res+=dfs(uu,vv);
		}
	}
	return res;
}
int T;int Cas=1; int len1,len2;
char s1[maxn],s2[maxn];
int main(){
	scanf("%d",&T);
	while (T--){
		pam1.init();pam2.init();
		scanf("%s%s",s1,s2);
		len1 = strlen(s1);len2 = strlen(s2);
		for (int i=0;i<len1;i++){
			pam1.add(s1[i]-'a');
		}
		for (int i=0;i<len2;i++){
			pam2.add(s2[i]-'a');
		}
		pam1.count();pam2.count();
		printf("Case #%d: %I64d\n",Cas++,dfs(0,0)+dfs(1,1));
	}
	return 0;
}

 

树链剖分

 

 

树链剖分+树状数组:

#include<bits/stdc++.h>  
using namespace std;  
const int INF = 0x3f3f3f3f;  
const int MAXN = 250000+100;  
struct Seg_Tree{  
    int sm[MAXN<<1];  
    inline int lowbit(int _x){return _x&(-_x);}  
    void build (int l,int r){  
        for (int i=l;i<=r;i++){  
            add(i,1);  
        }  
    }  
    void add(int x,int val){  
        while (x<=MAXN){  
            sm[x]+=val;  
            x+=lowbit(x);  
        }  
    }  
    int sum(int x){  
        int res =0;  
        while (x){  
            res+=sm[x];  
            x-=lowbit(x);  
        }  
        return res;  
    }  
    int query_sum(int l,int r){  
        return sum(r)-sum(l-1);  
    }  
}tree;  
int first[MAXN*2];int nxt[MAXN*2];int des[MAXN*2];  
int tpos[MAXN];int deep[MAXN];int top[MAXN];  
int fa[MAXN]; int wson[MAXN];  int size[MAXN];  
int n,q,tot=0,cnt=0;  char s[10];  
inline void add(int _u,int _v){  
    des[++tot] = _v;  
    nxt[tot] = first[_u];  
    first[_u] = tot;  
}  
void input(){  
    scanf("%d",&n);  
    for (int i=1;i<n;i++){  
        int u,v;  scanf("%d%d",&u,&v);  
        add(u,v);  add(v,u);  
    }  
}  
void dfs(int node,int father){  
    deep[node] = deep[father]+1;  
    fa[node] = father;  size[node] =1;  
    for (int t = first[node];t;t = nxt[t]){  
        int v = des[t];  
        if (v==father){  continue;  }  
        dfs(v,node);  
        if (size[v]>size[wson[node]]){  
      
  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值