模板合集(2)

本文总结了算法竞赛中常用的模板,包括数学、数据结构、字符串、图论等领域的经典算法实现,如快速傅里叶变换(FFT)、线性基、树链剖分、后缀数组、最小费用最大流等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(纯手打,持续更新中…)


数学

exGCD

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

FFT

非递归版

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define pi acos(-1.0)
#define N 4000050
using namespace std;
int n,m,r[N],l=0;
struct com
{
	double x,y;
	inline com operator +(com b) {com ret;ret.x=x+b.x,ret.y=y+b.y;return ret;}
	inline com operator -(com b) {com ret;ret.x=x-b.x,ret.y=y-b.y;return ret;}
	inline com operator *(com b) {com ret;ret.x=x*b.x-y*b.y,ret.y=y*b.x+x*b.y;return ret;}
}s[N*2],t[N*2];
inline void fft(com a[],int k)
{
	for (int i=0;i<n;i++) if (i<r[i]) swap(a[i],a[r[i]]);
	for (int i=1;i<n;i<<=1) 
	{
		com w,wn,X,Y;
		wn.x=cos(pi/i),wn.y=k*sin(pi/i);
		for (int j=0;j<n;j+=(i<<1))
		{
			w.x=1,w.y=0;
			for (int _=0;_<i;_++,w=w*wn)
			{
				X=a[j+_],Y=w*a[j+_+i];
				a[j+_]=X+Y,a[j+_+i]=X-Y;
			}
		}
	}
	if (k==-1) for (int i=0;i<n;i++) a[i].x/=n;
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=0;i<=n;i++) scanf("%lf",&s[i].x);
	for (int i=0;i<=m;i++) scanf("%lf",&t[i].x);
	for (m+=n,n=1;n<=m;n*=2) l++;
	for (int i=0;i<n;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
	fft(s,1),fft(t,1);
	for (int i=0;i<=n;i++) s[i]=s[i]*t[i];
	fft(s,-1);
	for (int i=0;i<=m;i++) printf("%.0lf ",s[i].x+0.4);
} 

线性求逆元

需要推一下公式

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 3000050
using namespace std;
typedef long long ll;
int inv[N],i,n,p;
int main()
{
	scanf("%d%d",&n,&p),inv[0]=0,inv[1]=1;
	printf("1\n");
	for (int i=2;i<=n;i++) inv[i]=(ll)(p-p/i)*inv[p%i]%p,printf("%d\n",inv[i]);
	return 0;
} 

NTT

g表示p的原根
本质上和FFT一样

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define p 1005060097
#define g 5
#define N 500050
using namespace std;
typedef long long ll;
ll a[N],b[N];
int n,m,r[N],l;
template<class _T>inline void read(_T &x)
{
	x=0;
	char ch=getchar();
	int f=0;
	while (!isdigit(ch)) {if (ch=='-') f=1;ch=getchar();}
	while (isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	if (f) x=-x;
}
inline ll qsm(ll x,ll y)
{
	ll ret=1;
	while (y)
	{
		if (y&1) ret=ret*x%p;
		x=x*x%p,y/=2;
	}
	return ret;
}
inline void ntt(ll a[],int k)
{
	for (int i=0;i<n;i++) if (i<r[i]) swap(a[i],a[r[i]]);
	for (int i=1;i<n;i<<=1)
	{
		ll w,wn,X,Y;
		if (k==1) wn=qsm(g,(p-1)/(i<<1));else wn=qsm(g,p-1-(p-1)/(i<<1));
		for (int j=0;j<n;j+=(i<<1))
		{
			w=1ll;
			for (int _=0;_<i;_++,w=w*wn%p)
			{
				X=a[j+_],Y=w*a[j+_+i]%p;
				a[j+_]=(X+Y)%p,a[j+_+i]=(X-Y+p)%p;
			}
		}
	}
	if (k==-1)
	{
		ll inv=qsm(n,p-2);
		for (int i=0;i<n;i++) a[i]=a[i]*inv%p;
	}
}
int main()
{
	read(n),read(m);
	for (int i=0;i<=n;i++) read(a[i]);
	for (int i=0;i<=m;i++) read(b[i]);
	for (m+=n,n=1,l=0;n<=m;n<<=1) l++;
	for (int i=0;i<n;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
	ntt(a,1),ntt(b,1); 
	for (int i=0;i<=n;i++) a[i]=a[i]*b[i]%p;
	ntt(a,-1);
	for (int i=0;i<=m;i++) printf("%lld ",a[i]);
}



FWT

#include<bits/stdc++.h>
#define p 998244353
#define inv 499122177
#define N 600050
using namespace std;
typedef long long ll;
ll n,a[N],b[N],c[N],nn;
inline void fwt(ll a[],int t,int k){
	ll X,Y;
	if (t==1){// or
		for (int i=1;i<n;i<<=1){
			for (int j=0;j<n;j++) if (i&j) a[j]=(a[j]+k*a[j^i]+p)%p;
		}
	}
	if (t==2){// and
		for (int i=1;i<=n;i<<=1){
			for (int j=0;j<n;j+=(i<<1))
				for (int _=0;_<i;_++){
					a[j+_]=(a[j+_]+k*a[j+_+i]+p)%p;
				}
		}
	}
	if (t==3){// xor
		for (int i=1;i<=n;i<<=1){
			for (int j=0;j<n;j+=(i<<1))
				for (int _=0;_<i;_++){
					if (k==1){
						X=a[j+_],Y=a[j+_+i];
						a[j+_]=(X+Y)%p,a[j+_+i]=(X-Y+p)%p;
					}
					else{
						X=a[j+_],Y=a[j+_+i];
						a[j+_]=(X+Y)%p*inv%p,a[j+_+i]=(X-Y+p)%p*inv%p;
					}
				}
		}
	}
}
int main(){
	scanf("%lld",&nn),n=1<<nn;
	for (int i=0;i<n;i++) scanf("%lld",&a[i]);
	for (int i=0;i<n;i++) scanf("%lld",&b[i]);
	fwt(a,1,1),fwt(b,1,1);
	for (int i=0;i<n;i++) c[i]=a[i]*b[i]%p;
	fwt(a,1,-1),fwt(b,1,-1),fwt(c,1,-1);
	for (int i=0;i<n;i++) printf("%lld ",c[i]);
	printf("\n");
	
	fwt(a,2,1),fwt(b,2,1);
	for (int i=0;i<n;i++) c[i]=a[i]*b[i]%p;
	fwt(a,2,-1),fwt(b,2,-1),fwt(c,2,-1);
	for (int i=0;i<n;i++) printf("%lld ",c[i]);
	printf("\n");
	
	fwt(a,3,1),fwt(b,3,1);
	for (int i=0;i<n;i++) c[i]=a[i]*b[i]%p;
	fwt(a,3,-1),fwt(b,3,-1),fwt(c,3,-1);
	for (int i=0;i<n;i++) printf("%lld ",c[i]*2%p);
	printf("\n");
}

高斯消元

带模数版本

inline void gauss(int n)
{
	for (int i=0;i<=n;i++){
		int k=i,del,Inv;
		for (int j=i+1;j<=n;j++) if (abs(a[j][i])>abs(a[k][i])) k=j;
		if (a[k][i]==0) return;
		if (k!=i) for (int j=i;j<=n+1;j++) swap(a[i][j],a[k][j]);
		del=a[i][i];
		Inv=qsm(del,mod-2);
		for (int j=i;j<=n+1;j++) a[i][j]=1ll*a[i][j]*Inv%mod;
		for (int k=0;k<=n;k++) if (k!=i){
			int del=a[k][i];
			for (int j=i;j<=n+1;j++) a[k][j]=(a[k][j]-1ll*del*a[i][j]%mod)%mod;	
		}
	}
}

线性基

#include<bits/stdc++.h>
#define N 100050
using namespace std;
typedef long long ll;
ll p[64],a[N],n,ans;
inline void cal(ll x){
    for (int i=62;i>=0;i--){
        if (!(x&(1ll<<i))) continue;
        if (!p[i]) {p[i]=x;break;}
        x^=p[i];
    }
}
int main(){
    scanf("%lld",&n),ans=0ll;
    for (int i=1;i<=n;i++) scanf("%lld",&a[i]),cal(a[i]);
    for (int i=62;i>=0;i--) if ((ans^p[i])>ans) ans^=p[i];
    printf("%lld\n",ans);
}

数据结构

LCT

其实我感觉不怎么能用上~

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define N 300050
using namespace std;
int w[N],n,m,x,y,opt;
struct lct
{
    int s[N][2],f[N],lz[N],t[N],q[N],top;
    inline bool isroot(int x) {return s[f[x]][0]!=x&&s[f[x]][1]!=x;}
    inline void pushup(int x) {t[x]=t[s[x][0]]^t[s[x][1]]^w[x];}
    inline void pushdown(int x) {if (lz[x]) lz[s[x][0]]^=1,lz[s[x][1]]^=1,lz[x]=0,swap(s[x][0],s[x][1]);}
    inline void rotate(int x,int k)
    {
        int y=f[x],z=f[y];
        s[y][!k]=s[x][k],f[x]=z;
        if (s[x][k]) f[s[x][k]]=y;
        if (!isroot(y)) s[z][y==s[z][1]]=x;
        s[x][k]=y,f[y]=x,pushup(y),pushup(x);
    }
    inline void splay(int x)
    {
        top=0,q[++top]=x;
        for (int i=x;!isroot(i);i=f[i]) q[++top]=f[i];
        for (int i=top;i;i--) pushdown(q[i]); 
        while (!isroot(x))
        {
            int y=f[x],z=f[y];
            if (isroot(y)) {rotate(x,x==s[y][0]);continue;}
            if (y==s[z][0]) 
            {
                if (x==s[y][0]) rotate(y,1),rotate(x,1);
                else rotate(x,0),rotate(x,1);
            }
            else
            {
                if (x==s[y][1]) rotate(y,0),rotate(x,0);
                else rotate(x,1),rotate(x,0);
            }
        }
    }
    inline void access(int x) {for (int i=0;x;i=x,x=f[x]) splay(x),s[x][1]=i,pushup(x);}
    inline void makeroot(int x) {access(x),splay(x),lz[x]^=1;}
    inline int find(int x) {access(x),splay(x);while (s[x][0]) x=s[x][0];return x;} 
    inline void split(int x,int y){makeroot(x),access(y),splay(y);}
    inline void cut(int x,int y) {split(x,y);if (x==s[y][0]) s[y][0]=0,f[x]=0;}
    inline void link(int x,int y) {makeroot(x),f[x]=y;}
}T;
inline void read(int &x)
{
    x=0;
    int f=1;
    char ch=getchar();
    while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
    while (isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    x=x*f;
}
int main()
{
    read(n),read(m);
    for (int i=1;i<=n;i++) read(w[i]),T.t[i]=w[i];
    while (m--)
    {
        read(opt);
        if (opt==0) read(x),read(y),T.split(x,y),printf("%d\n",T.t[y]);
        if (opt==1) {read(x),read(y);if (T.find(x)!=T.find(y)) T.link(x,y);}
        if (opt==2) {read(x),read(y);if (T.find(x)==T.find(y)) T.cut(x,y);}
        if (opt==3) read(x),read(y),T.access(x),T.splay(x),w[x]=y,T.pushup(x);
    }
    return 0;
}

splay

操作大概是齐全了

struct node
{
	int f,s[2],w,lz;
}a[maxn*2];
inline void rever(int l,int r) 
{
	l=kth(l),r=kth(r+2);
	splay(l,0),splay(r,l);
	a[a[a[root].s[1]].s[0]].lz^=1;
}
inline void rotate(int x,int k)
{
	int y=a[x].f,z=a[y].f;
	a[y].s[!k]=a[x].s[k];
	if (a[y].s[!k]) a[a[y].s[!k]].f=y;
	a[x].f=z;
	if (z) a[z].s[y==a[z].s[1]]=x;
	a[y].f=x,a[x].s[k]=y;
	pushup(y),pushup(x);
}
inline void splay(int x,int g)
{
	while (a[x].f!=g)
	{
		int y=a[x].f,z=a[y].f;
		if (z==g) {rotate(x,a[y].s[0]==x);continue;}
		if (y==a[z].s[0])
		{
			if (x==a[y].s[0]) rotate(y,1),rotate(x,1);
			else rotate(x,0),rotate(x,1);
		}
		else
		{
			if (x==a[y].s[1]) rotate(y,0),rotate(x,0);
			else rotate(x,1),rotate(x,0);
		}
	}
	if (!g) root=x;
}
inline void del(int x)
{
	splay(x);
	if (a[x].s[0]==-1) {root=a[x].s[1],a[a[x].s[1]].f=-1;return;}
	if (a[x].s[1]==-1) {root=a[x].s[0],a[a[x].s[0]].f=-1;return;}
	int y=a[x].s[0];
	while (a[y].s[1]!=-1) y=a[y].s[1];
	a[a[x].s[0]].f=-1,splay(y),a[y].s[1]=a[x].s[1],a[a[x].s[1]].f=y,root=y;
}
inline void pre(int x)
{
	tmp=root,p=-1,pnum=INF;
	while (1)
	{
		if (tmp==-1) return;
		if (a[tmp].w<x&&(x-a[tmp].w<pnum)) p=tmp,pnum=x-a[tmp].w;
		if (a[tmp].w<x) tmp=a[tmp].s[1];else tmp=a[tmp].s[0];
	}
}
inline void suc(int x)
{
	tmp=root,q=-1,qnum=INF;
	while (1)
	{
		if (tmp==-1) return;
		if (a[tmp].w>x&&(a[tmp].w-x<pnum)) q=tmp,qnum=a[tmp].w-x;
		if (a[tmp].w<x) tmp=a[tmp].s[1];else tmp=a[tmp].s[0];
	}
}
inline int kth(int x)
{
	int u=root;
	while (1)
	{
		pushdown(u);
		if (a[a[u].s[0]].sz>=x) u=a[u].s[0];
		else if (a[a[u].s[0]].sz+1==x) return u;
		else x-=a[a[u].s[0]].sz+1,u=a[u].s[1];
	}
}

另外一种写法:

inline void upd(int x){a[x].sz=a[a[x].s[0]].sz+a[a[x].s[1]].sz+1;}
inline void link(int u,int v,int k) {a[v].f=u,a[u].s[k]=v;}
inline void rot(int x){
	int u=a[x].f,k=(x==a[u].s[1]);
	link(a[u].f,x,u==a[a[u].f].s[1]);
	link(u,a[x].s[!k],k),link(x,u,!k);
	upd(u),upd(x);
}
inline void splay(int x){
	for (int u;u=a[x].f;rot(x)){
		if (a[u].f&&(u==a[a[u].f].s[1])==(x==a[a[x].f].s[1])) rot(u);
	}
	root=x;
}

树链剖分

理解了很好写
louguP3384

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define N 200050
#define mid ((l+r)>>1)
#define add(u,v) to[++Top]=head[u],head[u]=Top,w[Top]=v
#define For(x) for(int h=head[x],o=w[h];h;o=w[h=to[h]])
using namespace std;
typedef long long ll;
int Top=0,to[N<<1],w[N<<1],head[N<<1];
int a[N],b[N],t[N<<3],tag[N<<3];
int son[N],mxson[N],sz[N],d[N],f[N],id[N],top[N];
int n,m,p,x,y,z,u,v,cnt=0,root,opt,ans;
template <class _T>inline void read(_T &x)
{
	x=0;
	char ch=getchar();
	while (!isdigit(ch)) ch=getchar();
	while (isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
}
inline void pushup(int x) {t[x]=(t[x<<1]+t[x<<1|1])%p;}
inline void pushdown(int x,int l,int r)
{
	if (!tag[x]) return;
	tag[x<<1]+=tag[x],tag[x<<1|1]+=tag[x];
	t[x<<1]+=tag[x]*(mid-l+1),t[x<<1|1]+=tag[x]*(r-mid);
	tag[x]=0;
}
void build(int x,int l,int r)
{
	if (l==r) {t[x]=a[l]%p;return;}
	build(x<<1,l,mid),build(x<<1|1,mid+1,r),pushup(x);
}
void upd(int x,int l,int r,int ql,int qr)
{
	if (l==ql&&r==qr) {tag[x]+=z,t[x]=(t[x]+z*(r-l+1))%p;return;}
	pushdown(x,l,r);
	if (qr<=mid) upd(x<<1,l,mid,ql,qr);
	else if (ql>mid) upd(x<<1|1,mid+1,r,ql,qr);
	else upd(x<<1,l,mid,ql,mid),upd(x<<1|1,mid+1,r,mid+1,qr);
	pushup(x);
}
int query(int x,int l,int r,int ql,int qr)
{
	if (l==ql&&r==qr) return t[x]%p;
	pushdown(x,l,r);
	if (qr<=mid) return query(x<<1,l,mid,ql,qr);
	else if (ql>mid) return query(x<<1|1,mid+1,r,ql,qr);
	else return (query(x<<1,l,mid,ql,mid)+query(x<<1|1,mid+1,r,mid+1,qr))%p;
}
void dfs(int x,int fa)
{
	d[x]=d[fa]+1,f[x]=fa,sz[x]=1,mxson[x]=-1;//深度,父结点,大小,重儿子大小 
	For(x) if (o!=fa)
	{
		dfs(o,x),sz[x]+=sz[o];
		if (sz[o]>mxson[x]) son[x]=o,mxson[x]=sz[o];//重儿子 
	} 
}
void dfs2(int x,int topf)//当前链最顶端结点 
{
	id[x]=++cnt,a[cnt]=b[x],top[x]=topf;//当前点重标号
	if (!son[x]) return;
	dfs2(son[x],topf);
	For(x) if (o!=f[x]&&o!=son[x]) dfs2(o,o); 
}
int main()
{
	read(n),read(m),read(root),read(p);
	for (int i=1;i<=n;i++) read(b[i]);
	for (int i=1;i<n;i++) read(u),read(v),add(u,v),add(v,u);
	dfs(root,0),dfs2(root,root),build(1,1,n);
	while (m--)
	{
		read(opt);
		if (opt==1) 
		{
			read(x),read(y),read(z),z%=p;
			while (top[x]!=top[y])
			{
				if (d[top[x]]<d[top[y]]) swap(x,y);
				upd(1,1,n,id[top[x]],id[x]),x=f[top[x]];
			}
			if (d[x]<d[y]) swap(x,y);
			upd(1,1,n,id[y],id[x]);
		}
		if (opt==2)
		{
			read(x),read(y),ans=0;
			while (top[x]!=top[y])
			{
				if (d[top[x]]<d[top[y]]) swap(x,y);
				ans=(ans+query(1,1,n,id[top[x]],id[x]))%p,x=f[top[x]];
			}
			if (d[x]<d[y]) swap(x,y);
			ans=(ans+query(1,1,n,id[y],id[x]))%p,printf("%d\n",ans);
		}
		if (opt==3) read(x),read(z),upd(1,1,n,id[x],id[x]+sz[x]-1);
		if (opt==4) read(x),printf("%d\n",query(1,1,n,id[x],id[x]+sz[x]-1));
	}
}

主席树

Luogu3834

#include<bits/stdc++.h>
#define N 200050
#define mid ((l+r)>>1)
using namespace std;
struct node{int l,r,sum;}T[N*19];
struct dat{
	int x,n,w;
	inline bool operator <(dat b) const{return x<b.x;}
}a[N];
inline bool cmp(dat p,dat q) {return p.n<q.n;}
int root[N],n,q,L,R,x,lim,tot=0,b[N];
inline void upd(int &x,int y,int pos,int l=0,int r=lim){
	T[x=++tot]=T[y],T[x].sum=T[y].sum+1;
	if (l==r) return;
	if (pos<=mid) upd(T[x].l,T[y].l,pos,l,mid);else upd(T[x].r,T[y].r,pos,mid+1,r);
}
inline int query(int x,int y,int pos,int l=0,int r=lim){
	if (l==r) return l;
	if (T[T[y].l].sum-T[T[x].l].sum>=pos) return query(T[x].l,T[y].l,pos,l,mid);
	else return query(T[x].r,T[y].r,pos-(T[T[y].l].sum-T[T[x].l].sum),mid+1,r);
}
int main(){
	scanf("%d%d",&n,&q);
	for (int i=1;i<=n;i++) 
		scanf("%d",&a[i].x),a[i].n=i;
	sort(a+1,a+n+1);
	for (int i=1;i<=n;i++) if (a[i].x==a[i-1].x) a[i].w=a[i-1].w;else a[i].w=a[i-1].w+1,b[a[i].w]=a[i].x;
	lim=a[n].w,sort(a+1,a+n+1,cmp);
	for (int i=1;i<=n;i++) upd(root[i],root[i-1],a[i].w);
	while (q--){
		scanf("%d%d%d",&L,&R,&x);
		printf("%d\n",b[query(root[L-1],root[R],x)]);
	}
} 

树套树

施工中。。。


CDQ分治

bzoj3262:陌上花开

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define N 200050
#define lowbit(x) (x&(-x))
#define fi first
#define se second
using namespace std;
typedef pair<int,int> pii;
int ans[N],n,k,t[N],p[N];
pii b[N];
struct xx
{
	int x,y,z;
	bool operator <(xx b)const
	{
		if (x!=b.x) return x<b.x;
		if (y!=b.y) return y<b.y;
		return z<b.z;
	}
	bool operator ==(xx b)const
	{
		if (x==b.x&&y==b.y&&z==b.z) return 1;
		return 0;
	}
}a[N];
inline void add(int x,int val) {while (x<=k) t[x]+=val,x+=lowbit(x);}
inline int query(int x)
{
	int ret=0;
	while (x>=1) ret+=t[x],x-=lowbit(x);
	return ret;
}
template<class _T>inline void read(_T &x)
{
	x=0;
	char ch=getchar();
	int f=0;
	while (!isdigit(ch)) {if (ch=='-') f=1;ch=getchar();}
	while (isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	if (f) x=-x; 
}
inline void cdq(int l,int r)
{
	if (l>=r) return;
	int mid=(l+r)/2;
	cdq(l,mid);
	for (int i=l;i<=r;i++) b[i].fi=a[i].y,b[i].se=i;
	sort(b+l,b+r+1); //y z
	for (int i=l;i<=r;i++)
	{
		if (b[i].se==n) b[i].se=b[i].se;
		if (b[i].se<=mid) add(a[b[i].se].z,1);else ans[b[i].se]+=query(a[b[i].se].z);
	}
	for (int i=l;i<=r;i++) if (b[i].se<=mid) add(a[b[i].se].z,-1);
	cdq(mid+1,r);
}
int main()
{
	read(n),read(k);
	for (int i=1;i<=n;i++) read(a[i].x),read(a[i].y),read(a[i].z);
	sort(a+1,a+n+1); //x y z
	cdq(1,n);
	for (int i=n-1;i>=1;i--) if (a[i]==a[i+1]) ans[i]=ans[i+1];
	for (int i=1;i<=n;i++) p[ans[i]]++;
	for (int i=0;i<n;i++) printf("%d\n",p[i]);
}

字符串


后缀数组

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 1000050
char s[maxn];
int t[maxn],sa[maxn],x[maxn],y[maxn],p,m=128,n; 
using namespace std;
int main()
{
    scanf("%s",s),n=strlen(s),s[n++]=0;
    for (int i=0;i<m;i++) t[i]=0;
    for (int i=0;i<n;i++) t[x[i]=s[i]]++;    
    for (int i=1;i<m;i++) t[i]+=t[i-1]; 
    for (int i=n-1;i>=0;i--) sa[--t[s[i]]]=i;
    for (int j=1;p<n;j<<=1,m=p)
    {
        p=0;
        for (int i=n-j;i<n;i++) y[p++]=i;
        for (int i=0;i<n;i++) if (sa[i]>=j) y[p++]=sa[i]-j;
        for (int i=0;i<m;i++) t[i]=0;
        for (int i=0;i<n;i++) t[x[i]]++;    
        for (int i=1;i<m;i++) t[i]+=t[i-1];
        for (int i=n-1;i>=0;i--) sa[--t[x[y[i]]]]=y[i];
        swap(x,y),p=1;
        x[sa[0]]=0;
        for (int i=1;i<n;i++) if (y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]) x[sa[i]]=p-1;else x[sa[i]]=p++;
    } 
    for (int i=1;i<n;i++) printf("%d ",sa[i]+1);
} 

后缀自动机

应用较多,理解起来比较难

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream> 
#define maxn 2000050
typedef long long ll;
using namespace std;
struct node
{
    int f,len,go[30]; //father,length,edges
};
int sz[maxn],l,last,tot,c[maxn],a[maxn];
char s[maxn];
ll ans=0ll;
node t[maxn];
inline void extend(int c) 
{
	int now=++tot,p=last;  
	t[now].len=t[last].len+1;
	for (;p!=-1&&t[p].go[c]==0;p=t[p].f) t[p].go[c]=now;
	if (p==-1) t[now].f=0; 
	else
	{
		int q=t[p].go[c];
		if (t[q].len==t[p].len+1) t[now].f=q; 
		else 
		{
			int clone=++tot;  
			t[clone]=t[q],t[clone].len=t[p].len+1;
			for (;p!=-1&&t[p].go[c]==q;p=t[p].f) t[p].go[c]=clone;
			t[now].f=t[q].f=clone;
		}
	} 
	last=now,sz[now]=1;
}
inline void build()
{
	scanf("%s",s+1),last=tot=0,t[0].f=-1,l=strlen(s+1);
    for (int i=1;i<=l;i++) extend(s[i]-'a');
} 

AC自动机

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define N 1000050
using namespace std;
int tot,go[160*80][28],fail[160*80],q[N],cnt[160],n,tmp[160];
char S[160][80],t[N];
struct res
{
    int pos,num;
}val[160*80];
inline void build(char s[],int p)
{
    int x=0,len=strlen(s);
    for (int i=0;i<len;i++) if (go[x][s[i]-'a']) x=go[x][s[i]-'a'];else go[x][s[i]-'a']=++tot,x=tot;
    if (val[x].pos) val[x].num++;else val[x].pos=p,val[x].num=1;
}
inline void init()
{
    memset(go,0,sizeof(go)),memset(S,0,sizeof(S)),memset(fail,0,sizeof(fail));
    memset(cnt,0,sizeof(cnt)),memset(val,0,sizeof(val)),tot=0;
}
inline void getfail(){
	l=0,r=-1;
	for (int i=0;i<26;i++) if (go[0][i]) q[++r]=go[0][i];
	while (l<=r){
		x=q[l++];
		for (int i=0;i<26;i++) if (go[x][i]){
			for (y=fail[x];y&&!go[y][i];y=fail[y]); 
				fail[q[++r]=go[x][i]]=go[y][i];
		}
	}
}
inline void query(char s[])
{
    int x=0,len=strlen(s),ans=0;
    for (int i=0;i<len;++i)
    {
        while (x&&(!go[x][s[i]-'a'])) x=fail[x];
        x=go[x][s[i]-'a'];
        if (val[x].pos) ++cnt[val[x].pos],tmp[val[x].pos]=val[x].num;
    }
    for (int i=1;i<=n;i++) ans=max(ans,cnt[i]);
    printf("%d\n",ans);
    for (int i=1;i<=n;i++) if (cnt[i]==ans) for (int j=1;j<=tmp[i];j++) printf("%s\n",S[i]);
}
int main()
{
    while (1)
    {
        init(),scanf("%d",&n);
        if (!n) return 0;
        for (int i=1;i<=n;i++) scanf("%s",S[i]),build(S[i],i);
        scanf("%s",t),getfail(),query(t);
    }	
}

图论


树的重心

算不上什么模板,点分治专用

inline void getroot(int x,int fa)
{
	sz[x]=1,mxson[x]=0;
	For(x) if (!vis[o]&&o!=fa)
	{
		getroot(o,x),sz[x]+=sz[o];
		mxson[x]=max(mxson[x],sz[o]);
	}
	mxson[x]=max(tot-sz[x],mxson[x]);
	if (mxson[x]<mx) mx=mxson[x],root=x;
}
inline void solve(int x)
{
	vis[x]=1;
	...
	For(x) if (!vis[o])
	{
		tot=sz[o],root=0;
		getroot(o,0),solve(o);
	}
	...
}


最小费用最大流

使用SPFA的EK算法

#include<bits/stdc++.h>
#define For(x) for(int h=head[x],o=w[h],c=cost[h];h;o=w[h=to[h]],c=cost[h])
#define add(u,v,vv,c) to[++top]=head[u],head[u]=top,w[top]=v,cap[top]=vv,cost[top]=c
#define N 100050
#define INF 1000000000
using namespace std;
int top=1,head[N],to[N],w[N],cap[N],cost[N];
int bo[N],dis[N],flow[N],q[N],pre[N],l,r,x;
int u,v,vv,c,n,m,ans=0,maxflow=0,s,t;
template<class _T>inline void read(_T &x)
{
	x=0;
	char ch=getchar();
	while (!isdigit(ch)) ch=getchar();
	while (isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
}
inline bool spfa(int s,int t)
{
	memset(dis,0x7f7f7f,sizeof(dis)),memset(bo,0,sizeof(bo));
	q[l=r=0]=s,bo[s]=1,dis[s]=0,flow[s]=INF;
	while (l<=r)
	{
		x=q[l++],bo[x]=0;
		For(x) if (cap[h]&&dis[o]>dis[x]+c)
		{
			dis[o]=dis[x]+c,flow[o]=min(flow[x],cap[h]);
			pre[o]=h;
			if (!bo[o]) q[++r]=o,bo[o]=1;
		}
	}
	return dis[t]!=0x7f7f7f7f;
}
inline void upd(int s,int t)
{
	int x=t;
	while (x!=s)
	{
		int h=pre[x];
		cap[h]-=flow[t],cap[h^1]+=flow[t];
		x=w[h^1];
	}
	maxflow+=flow[t],ans+=flow[t]*dis[t];
}
inline void EK(int s,int t) {while (spfa(s,t)) upd(s,t);}
int main()
{
	read(n),read(m),read(s),read(t);
	while (m--) read(u),read(v),read(vv),read(c),add(u,v,vv,c),add(v,u,0,-c);
	EK(s,t),printf("%d %d\n",maxflow,ans);;
}

Tarjan算法

#include<bits/stdc++.h>
#define N 100050
#define add(u,v) to[++top]=head[u],head[u]=top,w[top]=v
#define For(x) for(int h=head[x],o=w[h];h;o=w[h=to[h]])
using namespace std;
int n,m,u,v;
int top=0,head[N<<1],to[N<<1],w[N<<1];
int dfn[N],low[N],cut[N],tot=0,ans=0;
inline void tarjan(int x,int fa){
    dfn[x]=low[x]=++tot;
    int child=0;
    For(x){
        if (!dfn[o]){
            tarjan(o,fa);
            low[x]=min(low[x],low[o]);
            if (low[o]>=dfn[x]&&x!=fa) cut[x]=1;
            if (x==fa) child++;
        }
        low[x]=min(low[x],dfn[o]);
    }
    if (child>=2&&x==fa) cut[x]=1;
}
int main(){
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++) scanf("%d%d",&u,&v),add(u,v),add(v,u); 
    for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i,i);
    for (int i=1;i<=n;i++) if (cut[i]) ans++;
    printf("%d\n",ans);
    for (int i=1;i<=n;i++) if (cut[i]) printf("%d ",i);
} 

计算几何


凸包

Graham算法

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 10050
#define INF 10000050
using namespace std;
inline double cross(double p1,double p2,double p3,double p4) {return p1*p4-p2*p3;}
struct point 
{
	double x,y;
	bool operator < (point q) const
	{
		if (x==0&&y==0) return 1;
		if (q.x==0&&q.y==0) return 0;
		return cross(q.x,q.y,x,y)<0;
	}
}a[maxn],s[maxn];
int top=0,n,minid;
double ans=0,px,py;
inline double dis(point p,point q) {return (sqrt((p.x-q.x)*(p.x-q.x)+(p.y-q.y)*(p.y-q.y)));}
double minx=INF;
int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
	for (int i=1;i<=n;i++) if (a[i].x<minx) minx=a[i].x,minid=i;
	px=a[minid].x,py=a[minid].y;
	for (int i=1;i<=n;i++) a[i].x-=px,a[i].y-=py;
	sort(a+1,a+n+1);
	s[1]=a[1],s[2]=a[2],s[3]=a[3],top=3;
	for (int i=4;i<=n;i++)
	{
		while (cross(a[i].x-s[top-1].x,a[i].y-s[top-1].y,a[i].x-s[top].x,a[i].y-s[top].y)<=0&&top>1) top--;
		s[++top]=a[i];
	}
	for (int i=1;i<top;i++) ans+=dis(s[i],s[i+1]);
	ans+=dis(s[1],s[top]);
	printf("%.2f",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值