zoukankan      html  css  js  c++  java
  • 各类模板

    四边形不等式

    定义函数 (f(l,r)) 满足四边形不等式为:对于所有 $ l le l' le r' le r $ ,满足 $f(l,r) ge f(l',r') , f(l,r)+f(l',r') ge f(l,r')+f(l',r) $
    对于状态转移方程 $f(i,j)=min egin{Bmatrix} f(i,k)+f(k+1,j) end{Bmatrix}+w(i,j) | i<=k<j $ ,有如下结论:

    1. 若w满足四边形不等式,则f满足四边形不等式
    2. 设s(l,r)表示区间[l,r]取最优值时k的值则:

    [s(l,r-1) le s(l,r) le s(l+1,r) ]

    要点:整体不小于局部,包含不小于相交,长度减1求范围。

    例子:P1880 [NOI1995]石子合并

    代码:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int oo=1e9+7;
    const int maxn=2007;
    int a[maxn],sum[maxn];
    int n,Fi[maxn][maxn],Fa[maxn][maxn],s[maxn][maxn];
    int main()
    {
    #ifdef local
    	freopen("pro.in","r",stdin);
    #endif
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		sum[i]=sum[i-1]+a[i]; s[i][i]=i; a[i+n]=a[i];
    	}
    	for(int i=1+n;i<=n*2;i++)
    	{
    		sum[i]=sum[i-1]+a[i];
    		s[i][i]=i;
    	}
    	for(int i=n*2-1;i>=1;i--)
    		for(int j=i+1;j<=n*2;j++)
    		{
    			int &pos=s[i][j],&val=Fi[i][j]; val=oo;
    			Fa[i][j]=max(Fa[i+1][j],Fa[i][j-1])+(sum[j]-sum[i-1]);
    			for(int k=s[i][j-1];k<=s[i+1][j];k++)
    			{
    				int tmp=Fi[i][k]+Fi[k+1][j]+(sum[j]-sum[i-1]);
    				if(tmp<val) val=tmp,pos=k;
    			}
    		}
    	int res_ma=0,res_mi=oo;
    	for(int i=1;i<=n;i++)
    	{
    		res_ma=max(res_ma,Fa[i][i+n-1]);
    		res_mi=min(res_mi,Fi[i][i+n-1]);
    	}
    	printf("%d
    %d
    ",res_mi,res_ma);
    	return 0;
    }
    

    斜率优化

    传送门


    manacher算法

    例子:P3805 【模板】manacher算法

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=51000005;
    int n,R[maxn],ans;
    char a[maxn],s[maxn<<1];
    int main()
    {
    #ifdef local
    	freopen("pro.in","r",stdin);
    #endif
    	scanf("%s",a); n=strlen(a);
    	s[0]=s[1]='#';
    	for(int i=0;i<n;i++) s[i*2+2]=a[i],s[i*2+3]='#';
    	n=2*n+2;
    	int maxright=0,mid=0;
    	for(int i=1;i<n;i++)
    	{
    		if(i<maxright) R[i]=min(R[mid*2-i],R[mid]+mid-i);
    		else R[i]=1;
    		while(s[i-R[i]]==s[i+R[i]]) ++R[i];
    		if(R[i]+i>maxright) { maxright=R[i]+i; mid=i; }
    	}
    	ans=1;
    	for(int i=0;i<n;i++) ans=max(ans,R[i]-1);
    	printf("%d
    ",ans);
    	return 0;
    }
    

    KMP 算法

    例子:P3375 【模板】KMP字符串匹配
    传送门


    字符串的最小表示

    例子:【模板】字符串的最小表示

    代码:

    #include<cstdio>
    #include<cstring>
    const int maxn=1e7+5;
    char s[maxn];
    int n;
    int getmin(char *s)
    {
    	int i=0,j=1,k=0,t;
    	while(i<n&&j<n&&k<n)
    	{
    		t=s[(i+k)%n]-s[(j+k)%n];
    		if(!t) k++;
    		else
    		{
    			if(t>0) i+=k+1; 
    			else j+=k+1;
    			if(i==j) j++;
    			k=0;
    		}
    	}
    	return (i<j?i:j)%n;
    }
    int main()
    {
    #ifdef local
    	freopen("pro.in","r",stdin);
    #endif
    	scanf("%s",s); n=strlen(s);
    	printf("%d
    ",getmin(s));
    	return 0;
    }
    

    AC自动机

    例子:P3808 【模板】AC自动机(简单版)

    代码:

    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int maxsize=1e6+5;
    const int sigsize=26;
    int n; char str[maxsize];
    struct ACMachine
    {
    	int e[maxsize][sigsize],f[maxsize],val[maxsize],last[maxsize],cnt;
    	void insert(char *s)
    	{
    		int n=strlen(s),p=0;
    		for(int i=0;i<n;i++)
    		{
    			if(!e[p][s[i]-'a']) e[p][s[i]-'a']=++cnt;
    			p=e[p][s[i]-'a'];
    		}
    		++val[p];
    	}
    	void build()
    	{
    		queue<int> Q;
    		for(int c=0;c<sigsize;c++) if(e[0][c]) Q.push(e[0][c]);
    		while(Q.size())
    		{
    			int u=Q.front(),k=f[u]; Q.pop();
    			for(int c=0;c<sigsize;c++)
    			{
    				int &v=e[u][c];
    				if(!v) { v=e[k][c]; continue; }
    				Q.push(v);
    				f[v]=e[k][c]; last[v]=val[f[v]]?f[v]:last[f[v]];
    			}
    		}
    	}
    	int query(char *s)
    	{
    		int n=strlen(s),p=0,res=0;
    		for(int i=0;i<n;i++)
    		{
    			p=e[p][s[i]-'a'];
    			res+=val[p]; val[p]=0;
    			int v=p;
    			while(last[v])
    			{
    				v=last[v];
    				res+=val[v]; val[v]=0;
    			}
    		}
    		return res;
    	}
    }AC;
    int main()
    {
    #ifdef local
    	freopen("pro.in","r",stdin);
    #endif
    	scanf("%d",&n);
    	while(n-->0) scanf("%s",str),AC.insert(str);
    	AC.build();
    	scanf("%s",str);
    	printf("%d
    ",AC.query(str));
    	return 0;
    }
    

    DLX算法

    例子:UVA1309 Sudoku

    关键代码:

    struct DLX
    {
    	int n,sz;
    	int s[maxn];
    	int row[maxnode],col[maxnode];
    	int U[maxnode],D[maxnode],L[maxnode],R[maxnode];
    	int ansd,ans[300];
    	void init(int n)
    	{
    		this->n=n; sz=n+1;
    		memset(s,0,sizeof(s));
    		for(int i=0;i<=n;i++) { U[i]=i; D[i]=i; L[i]=i-1; R[i]=i+1; }
    		L[0]=n; R[n]=0;
    	}
    	inline void push_back(int r,const vector<int> &cols)
    	{
    		int first=sz,szc=cols.size();
    		for(int i=0;i<szc;i++)
    		{
    			int c=cols[i];
    			L[sz]=sz-1; R[sz]=sz+1; D[sz]=c; U[sz]=U[c];
    			D[U[sz]]=sz; U[c]=sz;
    			row[sz]=r; col[sz]=c;
    			++s[c]; ++sz;
    		}
    		R[sz-1]=first; L[first]=sz-1;
    	}
    	#define For(i,A,s) for(int i=A[s];i!=s;i=A[i])
    	inline void remove(int c)
    	{
    		L[R[c]]=L[c]; R[L[c]]=R[c];
    		For(i,D,c) For(j,R,i) { U[D[j]]=U[j]; D[U[j]]=D[j]; --s[col[j]]; }
    	}
    	inline void restore(int c)
    	{
    		For(i,U,c) For(j,L,i) { ++s[col[j]]; U[D[j]]=j; D[U[j]]=j; }
    		L[R[c]]=c; R[L[c]]=c;
    	}
    	bool dfs(int d)
    	{
    		if(R[0]==0) { ansd=d; return true; }
    		int c=R[0];
    		For(i,R,0) if(s[i]<s[c]) c=i;
    		remove(c);
    		For(i,D,c)
    		{
    			ans[d]=row[i];
    			For(j,R,i) remove(col[j]);
    			if(dfs(d+1)) return true;
    			For(j,L,i) restore(col[j]);
    		}
    		restore(c);
    		return false;
    	}
    	bool solve(vector<int> &res)
    	{
    		res.clear();
    		if(!dfs(0)) return false;
    		for(int i=0;i<ansd;i++) res.push_back(ans[i]);
    		return true;
    	}
    };
    

    欧拉回路

    int cnt=0,res[maxn];
    void dfs(int u)
    {
    	for(int it=G[u];it;it=e[it].next)
    		if(e[it].v>=0)//not deleted
    		{
    			int v=e[it].v;
    			du[u]--; du[e[it].v]--;
    			e[it].v=-1;
    			e[it^1].v=-1;
    			dfs(v);
    		}
    	res[cnt++]=u;
    }
    
    while(cnt>0) printf("%d ",res[--cnt]);
    

    矩阵树定理

    度数矩阵D:是一个(N imes N)的矩阵,其中(D[i][j]=0 (i eq j),D[i][i]=)节点(i)的度数。

    邻接矩阵A:是一个(N imes N)的矩阵,其中(A[i][j]=)(i,j)之间的边数。

    基尔霍夫Kirchhoff矩阵K=D-A

    该无向图的生成树的个数等于矩阵K去掉一行一列后的行列式的绝对值。


    最小生成树(瓶颈生成树)

    例子:P3366 【模板】最小生成树

    代码:

    Prim:
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    using namespace std;
    const int maxn=5005;
    const int maxm=200005;
    struct Edge { int v,w; Edge *next; };
    Edge *G[maxn],mem[maxm*2],*ecnt=mem;
    inline void AddEdge(int u,int v,int w) { ecnt->v=v; ecnt->w=w; ecnt->next=G[u]; G[u]=ecnt++; }
    int n,m,inq,res;
    typedef pair<int,int> PII;
    #define mkp make_pair
    priority_queue<PII,vector<PII>,greater<PII> > Q;
    int dis[maxn];
    bool vis[maxn];
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=0;i<m;i++)
    	{
    		int a,b,c;
    		scanf("%d%d%d",&a,&b,&c);
    		AddEdge(a,b,c); AddEdge(b,a,c);
    	}
    	memset(dis,127,sizeof(dis));
    	dis[1]=0;
    	Q.push(mkp(0,1));
    	while(!Q.empty()&&inq<n)
    	{
    		int u=Q.top().second,w=Q.top().first;
    		Q.pop();
    		if(vis[u]) continue;
    		vis[u]=true;
    		res+=w;
    		inq++;
    		for(Edge *it=G[u];it;it=it->next)
    			if(it->w<dis[it->v]) dis[it->v]=it->w,Q.push(mkp(dis[it->v],it->v));
    	}
    	if(inq==n) printf("%d
    ",res);
    	else printf("orz
    ");
    	return 0;
    }
    

    有向图的强连通分量

    例子:UVA12167 Proving Equivalences

    关键代码:

    vector<int> G[maxn];
    int dfn[maxn],lowlink[maxn],sccno[maxn],dfs_cnt,scc_cnt;
    stack<int> S;
    void dfs(int u)
    {
    	dfn[u]=lowlink[u]=++dfs_cnt;
    	S.push(u);
    	for(int i=0;i<G[u].size();i++)
    	{
    		int v=G[u][i];
    		if(!dfn[v])
    		{
    			dfs(v);
    			lowlink[u]=min(lowlink[u],lowlink[v]);
    		}
    		else if(!sccno[v]) lowlink[u]=min(lowlink[u],dfn[v]);
    	}
    	if(lowlink[u]==dfn[u])
    	{
    		scc_cnt++;
    		while(true)
    		{
    			int x=S.top(); S.pop();
    			sccno[x]=scc_cnt;
    			if(x==u) break;
    		}
    	}
    }
    
    dfs_cnt=0; scc_cnt=0;
    memset(sccno,0,sizeof(sccno));
    memset(dfn,0,sizeof(dfn));
    for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
    

    无向图最小环

    关键代码:

    for(int k=1;k<=n;++k)
    {
    	for(int i=1;i<k;++i)
    		for(int j=1;j<i;++j)
    			if((dis[i][j]^oo)&&(G[j][k]^oo)&&(G[k][i]^oo))
    				res=min(res,dis[i][j]+G[j][k]+G[k][i]);
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<i;++j)
    		{
    			int tmp=dis[i][k]+dis[k][j];
    			if(tmp<dis[i][j]) dis[i][j]=dis[j][i]=tmp;
    		}
    }
    

    AOE网关键路径

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    template<typename T> inline void read(T& t)
    {
    	t=0; int ch,f=false;
    	while(ch=getchar(),!((ch>='0'&&ch<='9')||ch=='-'));
    	if(ch=='-') f=true,ch=getchar();
    	t=ch^48;
    	while(ch=getchar(),ch>='0'&&ch<='9') t=t*10+(ch^48);
    	if(f) t=-t;
    }
    template<typename T,typename... Args> inline void read(T& t,Args&... args) { read(t); read(args...); }
    const int maxn=1005;
    const int maxm=1000005;
    const int oo=0x3f3f3f3f;
    struct Edge { int v,w; Edge *next; };
    Edge mem[maxm],*G[maxn],*ecnt=mem;
    inline void AddEdge(int u,int v,int w) { ecnt->v=v; ecnt->w=w; ecnt->next=G[u]; G[u]=ecnt++; }
    int du[maxn],stk1[maxn],top1,stk2[maxn],top2;
    int ve[maxn],vl[maxn];
    int main()
    {
    	int n,m,u,v,w,res=0;
    	read(n,m);
    	while(m-->0)
    	{
    		read(u,v,w);
    		AddEdge(u,v,w);
    		++du[v];
    	}
    	for(int i=1;i<=n;i++) if(!du[i]) stk2[top2++]=stk1[top1++]=i;
    	while(top1>0)
    	{
    		int u=stk1[--top1];
    		for(Edge *it=G[u];it;it=it->next)
    		{
    			ve[it->v]=max(ve[it->v],ve[u]+it->w);
    			if(--du[it->v]==0) stk2[top2++]=stk1[top1++]=it->v;
    		}
    	}
    	memset(vl,oo,sizeof(vl));
    	vl[stk2[n-1]]=ve[stk2[n-1]];
    	while(top2>0)
    	{
    		int u=stk2[--top2];
    		for(Edge *it=G[u];it;it=it->next) vl[u]=min(vl[u],vl[it->v]-it->w);
    	}
    	for(int i=1;i<=n;i++) for(Edge *it=G[i];it;it=it->next)
    		if(ve[i]/*ee*/==vl[it->v]-it->w/*el*/) res+=it->w;
    	printf("%d
    ",res);
    	return 0;
    }
    

    后缀数组

    概念:

    1. 后缀i:从第i个字符开始的后缀
    2. sa[i]:第i小的后缀
    3. rank[i]:后缀i在sa中的下标
    4. height[i]=LCP(后缀sa[i],后缀sa[i-1])
    5. 后缀j和后缀k的LCP=RMQ(height,rank[j]+1,rank[k])

    例子:P3809 【模板】后缀排序

    关键代码:

    char s[maxn];
    int sa[maxn],t[maxn],t2[maxn],c[maxn],n;
    int rnk[maxn],height[maxn];
    void build_sa(int sig)
    {
    	int *x=t,*y=t2;
    	memset(c,0,sizeof(c));
    	for(int i=0;i<n;i++) c[x[i]=s[i]]++;
    	for(int i=1;i<sig;i++) c[i]+=c[i-1];
    	for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
    	for(int k=1;k<=n;k<<=1)
    	{
    		int p=0;
    		for(int i=n-k;i<n;i++) y[p++]=i;
    		for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
    		
    		memset(c,0,sizeof(c));
    		for(int i=0;i<n;i++) c[x[y[i]]]++;
    		for(int i=1;i<sig;i++) c[i]+=c[i-1];
    		for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
    		
    		swap(x,y);
    		p=1; x[sa[0]]=0;
    		for(int i=1;i<n;i++)
    			x[sa[i]]=(y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++);
    		if(p>=n) break;
    		sig=p;
    	}
    }
    void getHeight()
    {
    	int i,j,k=0;
    	for(i=0;i<n;i++) rnk[sa[i]]=i;
    	for(i=0;i<n;i++)
    	{
    		if(rnk[i]==0) continue;
    		if(k) k--;
    		j=sa[rnk[i]-1];
    		while(i+k<n&&j+k<n&&s[i+k]==s[j+k]) k++;
    		height[rnk[i]]=k;
    	}
    }
    

    点分治

    例子:P3806 【模板】点分治1

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=10005;
    struct Edge { int v,w; Edge *next; };
    Edge mem[maxn*2],*G[maxn],*ecnt=mem;
    inline void AddEdge(int u,int v,int w) { ecnt->v=v; ecnt->w=w; ecnt->next=G[u]; G[u]=ecnt++; }
    int n,m,k,res,Siz,rt,cnt;
    bool vis[maxn];
    int f[maxn],sz[maxn],dis[maxn];
    void GetRoot(int u,int fa)
    {
    	f[u]=0; sz[u]=1;
    	for(Edge *it=G[u];it;it=it->next)
    	{
    		int v=it->v;
    		if(vis[v]||v==fa) continue;
    		GetRoot(v,u);
    		f[u]=max(f[u],sz[v]); sz[u]+=sz[v];
    	}
    	f[u]=max(f[u],Siz-f[u]);
    	if(f[u]<f[rt]) rt=u;
    }
    void GetDis(int u,int fa,int d)
    {
    	for(Edge *it=G[u];it;it=it->next)
    	{
    		int v=it->v;
    		if(vis[v]||v==fa) continue;
    		dis[++cnt]=d+it->w;
    		GetDis(v,u,dis[cnt]);
    	}
    }
    int GetAns(int u,int d)
    {
    	dis[cnt=1]=d;
    	GetDis(u,0,d);
    	sort(dis+1,dis+1+cnt);
    	int l=1,res=0;
    	while(l<cnt&&dis[l]+dis[cnt]<k) ++l;
    	while(l<cnt&&k-dis[l]>=dis[l])
    	{
    		auto it=equal_range(dis+l+1,dis+cnt+1,k-dis[l]);
    		res+=it.second-it.first;
    		++l;
    	}
    	return res;
    }
    void dfs(int u)
    {
    	vis[u]=true; res+=GetAns(u,0);
    	for(Edge *it=G[u];it;it=it->next)
    	{
    		int v=it->v;
    		if(vis[v]) continue;
    		res-=GetAns(v,it->w);
    		Siz=sz[v]; rt=0;
    		GetRoot(v,u);
    		dfs(v);
    	}
    }
    int main()
    {
    #ifdef local
    	freopen("pro.in","r",stdin);
    #endif
    	scanf("%d%d",&n,&m);
    	int a,b,c;
    	for(int i=0;i<n-1;i++)
    	{
    		scanf("%d%d%d",&a,&b,&c);
    		AddEdge(a,b,c); AddEdge(b,a,c);
    	}
    	while(m-->0)
    	{
    		scanf("%d",&k);
    		res=0; memset(vis,0,sizeof(vis)); Siz=n; sz[0]=1e9+7;
    		dfs(1);
    		puts(res?"AYE":"NAY");
    	}
    	return 0;
    }
    

    01分数规划

    算法模板:

    • 二分法(通用算法,验证解快时使用)
    L:=...;R:=...;
    Repeat
      Mid:=(L+R)/2;
      For I=1..X do D[i]:=A[i]-Mid*B[i];//根据Mid计算D数组
      if 检查(Mid)成功 then L:=Mid
      else R:=Mid;
    Until abs(L-R)<Eps;
    
    • Dinkelbach算法(求解快时使用)
    L:=随便什么东西;
    Repeat
      Ans:=L;
      For I=1..X do D[i]:=A[i]-L*B[i];//根据L计算D数组
      检查解并记录;
      p:=0;q:=0;
      for I=每一个元素 do 
    	 如果元素I在解中
    		begin
    		  p:=p+A[i];q:=q+B[i];
    		end;
      L:=p/q;//更新解
    Until abs(Ans-L)<Eps;
    

    线性筛与积性函数

    算法模板:

    f[1]=1; memset(isp,true,sizeof(isp));
    cnt=0;
    for(int i=2;i<=n;i++)
    {
    	if(isp[i])
    	{
    		p[cnt++]=i;
    		根据定义初始化;//eg. phi[i]=i-1;
    	}
    	for(int j=0;j<cnt&&i*p[j]<=n;j++)
    	{
    		isp[i*p[j]]=false;
    		if(i%p[j]==0)
    		{
    			特殊处理;//eg. phi[i*p[j]]=phi[i]*p[j];
    			break;
    		}
    		else f[i*p[j]]=f[i]*f[p[j]];
    	}
    }
    

    long long 乘法取模

    inline LL mmul(LL a, LL b, LL m)
    {
    	LL d=((long double)a/m*b+0.5);//注意!不加0.5可能会有精度问题!
    	LL r=a*b-d*m;
    	return r<0?r+m:r;
    }
    

    分组背包

    伪代码:

    for 所有的组k
    	for v=V..0
    		for 所有的i属于组k
    			f[v]=max{f[v],f[v-c[i]]+w[i]}
    

    泛化物品

    定义:有一个物品,它消耗i的代价时的收益是G[i]

    • 泛化物品的和:合并两个泛化物品的运算
    G[i]=max(G1[j-k]+G2[k]) (C>=j>=k>=0)
    
    • 泛化物品与普通物品的和:普通背包
    • 泛化物品的并(貌似用不到,暂时跳过)

    树形依赖背包(后序遍历优化)

    例子:P1064 金明的预算方案

    代码:

    #include<cstdio>
    #include<vector>
    #include<algorithm>
    using namespace std;
    template<typename T> inline void read(T& t)
    {
    	t=0; int ch,f=false;
    	while(ch=getchar(),!((ch>='0'&&ch<='9')||ch=='-'));
    	if(ch=='-') f=true,ch=getchar();
    	t=ch^48;
    	while(ch=getchar(),ch>='0'&&ch<='9') t=t*10+(ch^48);
    	if(f) t=-t;
    }
    template<typename T,typename... Args> inline void read(T& t,Args&... args) { read(t); read(args...); }
    const int maxn=65;
    const int maxm=32005;
    int f[maxn][maxm];
    vector<int> son[maxn];
    int V[maxn],W[maxn];
    int n,m,v,p,q;
    int sz[maxn],suf[maxn],cnt;
    void dfs(int u)
    {
    	sz[u]=1;
    	for(int i=0;i<son[u].size();i++) { dfs(son[u][i]); sz[u]+=sz[son[u][i]]; }
    	suf[++cnt]=u;
    }
    int main()
    {
    #ifdef local
    	freopen("pro.in","r",stdin);
    #endif
    	read(m,n);
    	for(int i=1;i<=n;i++)
    	{
    		read(v,p,q);
    		V[i]=v*p; W[i]=v; son[q].push_back(i);
    	}
    	dfs(0);
    	for(int i=1;i<=cnt;i++)
    	{
    		int now=suf[i];
    		for(int j=m;j>=0;j--)
    			if(j>=W[now]) f[i][j]=max(f[i-sz[now]][j],f[i-1][j-W[now]]+V[now]);
    			else f[i][j]=f[i-sz[now]][j];
    	}
    	printf("%d
    ",f[cnt][m]);
    	return 0;
    }
    

    计算几何:传送门


    数论:传送门


    Dinic

    例子:P3376 【模板】网络最大流

    代码:

    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<queue>
    #include<algorithm>
    using namespace std;
    template<typename T> inline void read(T& t)
    {
    	t=0; bool f=false; char ch;
    	while(ch=getchar(),!((ch>='0'&&ch<='9')||ch=='-'));
    	if(ch=='-') f=true,ch=getchar();
    	t=ch-'0';
    	while(ch=getchar(),ch>='0'&&ch<='9') t=t*10+ch-'0';
    	if(f) t=-t;
    }
    template<typename T,typename... Args> inline void read(T& t,Args&... args) { read(t); read(args...); }
    const int maxn=10005;
    const int oo=1e9+7;
    struct Edge { int from,to,cap,flow; };
    struct Dinic
    {
    	int n,m,s,t;
    	vector<Edge> edges;
    	vector<int> G[maxn];
    	bool vis[maxn];
    	int d[maxn],pos[maxn];
    	inline void AddEdge(int u,int v,int c)
    	{
    		edges.push_back((Edge){u,v,c,0});
    		edges.push_back((Edge){v,u,0,0});
    		m=edges.size();
    		G[u].push_back(m-2);
    		G[v].push_back(m-1);
    	}
    	inline bool BFS()
    	{
    		memset(vis,0,sizeof(vis)); memset(d,0x3f,sizeof(d));
    		queue<int> Q;
    		Q.push(s); vis[s]=true; d[s]=0;
    		while(Q.size())
    		{
    			int u=Q.front(); Q.pop();
    			for(int i=0;i<G[u].size();i++)
    			{
    				Edge &e=edges[G[u][i]];
    				if(!vis[e.to]&&e.cap>e.flow)
    				{
    					vis[e.to]=true;
    					d[e.to]=d[u]+1;
    					Q.push(e.to);
    				}
    			}
    		}
    		return vis[t];
    	}
    	inline int DFS(int u,int a)
    	{
    		if(u==t||a==0) return a;
    		int flow=0,f;
    		for(int &i=pos[u];i<G[u].size();i++)
    		{
    			Edge &e=edges[G[u][i]];
    			if(d[u]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)
    			{
    				e.flow+=f; flow+=f;
    				edges[G[u][i]^1].flow-=f; a-=f;
    				if(a==0) break;
    			}
    		}
    		return flow;
    	}
    	int MaxFlow(int s,int t)
    	{
    		this->s=s; this->t=t;
    		int flow=0;
    		while(BFS())
    		{
    			memset(pos,0,sizeof(pos));
    			flow+=DFS(s,oo);
    		}
    		return flow;
    	}
    }dinic;
    int n,m,s,t,u,v,c;
    int main()
    {
    #ifdef local
    	freopen("pro.in","r",stdin);
    #endif
    	read(n,m,s,t);
    	while(m-->0)
    	{
    		read(u,v,c);
    		dinic.AddEdge(u,v,c);
    	}
    	printf("%d
    ",dinic.MaxFlow(s,t));
    	return 0;
    }
    

    快排

    #include<cstdio>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
    const int maxn=100005;
    int n,a[maxn];
    void quicksort(int L,int R)
    {
    	if(L>=R) return;
    	int i=L,j=R;
    	swap(a[L],a[L+rand()%(R-L+1)]);
    	while(i<j)
    	{
    		while(j>i&&a[j]>=a[L]) j--;
    		while(j>i&&a[i]<=a[L]) i++;
    		swap(a[i],i==j?a[L]:a[j]);
    	}
    	quicksort(L,i-1);
    	quicksort(i+1,R);
    }
    int main()
    {
    #ifdef local
    	freopen("pro.in","r",stdin);
    #endif
    	scanf("%d",&n);
    	for(int i=0;i<n;i++) scanf("%d",&a[i]);
    	srand(187);
    	quicksort(0,n-1);
    	for(int i=0;i<n;i++) printf("%d ",a[i]); puts("");
    	return 0;
    }
    

    归并排序 & 求逆序对

    #include<cstdio>
    #include<cstring>
    const int maxn=5e5+5;
    int n; long long res;
    int a[maxn],b[maxn];
    void GB(int *a,int *b,int len)
    {
    	if(len<=1) return;
    	int M=len/2,p1=0,p2=M,p=0;
    	GB(a,b,M); GB(a+M,b+M,len-M);
    	while(p1<M&&p2<len)
    	{
    		if(a[p1]<=a[p2]) b[p++]=a[p1++];
    		else res+=M-p1,b[p++]=a[p2++];
    	}
    	while(p1<M) b[p++]=a[p1++];
    	while(p2<len) b[p++]=a[p2++];
    	memcpy(a,b,len<<2);
    }
    int main()
    {
    #ifdef local
    	freopen("pro.in","r",stdin);
    #endif
    	scanf("%d",&n);
    	for(int i=0;i<n;i++) scanf("%d",&a[i]);
    	GB(a,b,n);
    	printf("%lld
    ",res);
    	return 0;
    }
    

    基数排序

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=100005;
    int n,a[maxn],b[maxn],cnt[10];
    void bksort()
    {
    	int mx=a[0];
    	for(int i=1;i<n;i++) mx=max(mx,a[i]);
    	for(int exp=1;mx/exp>0;exp*=10)
    	{
    		for(int i=0;i<10;i++) cnt[i]=0;
    		for(int i=0;i<n;i++) cnt[a[i]/exp%10]++;
    		for(int i=1;i<10;i++) cnt[i]+=cnt[i-1];
    		for(int i=n-1;i>=0;i--) b[--cnt[a[i]/exp%10]]=a[i];
    		memcpy(a,b,n<<2);
    	}
    }
    int main()
    {
    #ifdef local
    	freopen("pro.in","r",stdin);
    #endif
    	scanf("%d",&n);
    	for(int i=0;i<n;i++) scanf("%d",&a[i]);
    	bksort();
    	for(int i=0;i<n;i++) printf("%d ",a[i]); puts("");
    	return 0;
    }
    

    LCA

    例题:P3379 【模板】最近公共祖先(LCA)

    Tarjan

    #include<cstdio>
    template<typename T>
    inline void read(T& t)
    {
        t=0; bool f=false; char ch;
        while(ch=getchar(),!((ch>='0'&&ch<='9')||ch=='-'));
        if(ch=='-') f=true,ch=getchar();
        t=ch-'0';
        while(ch=getchar(),ch>='0'&&ch<='9') t=t*10+ch-'0';
        if(f) t=-t;
    }
    template<typename T,typename... Args>
    inline void read(T& t,Args&... args)
    {
        read(t); read(args...);
    }
    template<typename T>
    inline void write(T t)
    {
        if(t==0) { putchar('0'); return; }
        char stk[50]; int top;
        if(t<0) putchar('-'),t=-t;
        while(t>0) stk[top++]=t%10+'0',t/=10;
        while(top>0) putchar(stk[--top]);
    }
    
    const int maxn=500005;
    const int maxm=500000*2+5;
    struct Rec { int to,lca; Rec *next; };
    Rec edge[maxm],*E[maxn],*ecnt=edge;
    Rec query[maxm],*Q[maxn],*qcnt=query;
    inline void AddEdge(Rec **G,Rec* &ecnt,int from,int to)
    { ecnt->to=to; ecnt->next=G[from]; G[from]=ecnt++; }
    int n,m,s;
    bool vis[maxn];
    int fa[maxn];
    inline int ff(int x)
    {
        int a=x,b;
        while(x!=fa[x]) x=fa[x];
        while(a!=x)
        {
            b=fa[a];
            fa[a]=x;
            a=b;
        }
        return x;
    }
    void dfs(int u)
    {
        fa[u]=u;
        vis[u]=true;
        for(Rec *it=E[u];it;it=it->next)
            if(!vis[it->to])
            {
                dfs(it->to);
                fa[it->to]=u;
            }
        for(Rec *it=Q[u];it;it=it->next)
            if(vis[it->to])
            {
                it->lca=ff(it->to);
                (query+((it-query)^1))->lca=it->lca;
            }
    }
    int main()
    {
        read(n,m,s);
        for(int i=0;i<n-1;i++)
        {
            int a,b; read(a,b);
            AddEdge(E,ecnt,a,b); AddEdge(E,ecnt,b,a);
        }
        for(int i=0;i<m;i++)
        {
            int a,b; read(a,b);
            AddEdge(Q,qcnt,a,b); AddEdge(Q,qcnt,b,a);
        }
        dfs(s);
        for(int i=0;i<m;i++) { write(query[i*2].lca); putchar('
    '); }
        return 0;
    }
    

    倍增

    #include<cstdio>
    #include<vector>
    #include<cstdlib>
    using namespace std;
    const int maxn=500005;
    int n,m,s;
    vector<int> G[maxn];
    int dep[maxn],anc[maxn][30];
    void cal(int o,int fa)
    {
        dep[o]=dep[anc[o][0]]+1;
        for(int i=1;i<=25;i++) anc[o][i]=anc[anc[o][i-1]][i-1];
        for(int ch:G[o])
            if(ch!=fa)
            {
                anc[ch][0]=o;
                cal(ch,o);
            }
    }
    inline int getLCA(int a,int b)
    {
        if(a==b) return a;
        if(dep[b]>dep[a]) swap(a,b);
        for(int i=25;i>=0;i--)
            if(dep[anc[a][i]]>=dep[b]) a=anc[a][i];
        if(a==b) return a;
        for(int i=25;i>=0;i--)
            if(anc[a][i]!=anc[b][i]) a=anc[a][i],b=anc[b][i];
        return anc[a][0];
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&s);
        for(int i=0;i<n-1;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            G[x].push_back(y); G[y].push_back(x);
        }
        cal(s,0);
        while(m-->0)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%d
    ",getLCA(x,y));
        }
        return 0;
    }
    

    RMQ

    1. 构造这颗树的欧拉序(每次经过一个节点都要记录下来,包括回退时)
    2. 在(u,v)的欧拉序中第一次出现的位置之间的深度最小的点即为LCA

    欧拉序:

    vector<int> a;
    void dfs(int u)
    {
    	a.push_back(u);
    	for(Edge *it=G[u];it;it=it->nxt)
    	{
    		dfs(it->v);
    		a.push_back(u);
    	}
    }
    
  • 相关阅读:
    Android-使用AIDL挂断电话
    新变化---转战新博客
    Spring Cloud Config 分布式配置中心【Finchley 版】
    Spring Boot2.0 整合 Kafka
    Spring Cloud 分布式链路跟踪 Sleuth + Zipkin + Elasticsearch【Finchley 版】
    Spring MVC 5 + Thymeleaf 基于Java配置和注解配置
    【机器学习】使用gensim 的 doc2vec 实现文本相似度检测
    【机器学习】SKlearn + XGBoost 预测 Titanic 乘客幸存
    【深度学习】keras + tensorflow 实现猫和狗图像分类
    iScroll.js 向上滑动异步加载数据回弹问题
  • 原文地址:https://www.cnblogs.com/happyZYM/p/11379879.html
Copyright © 2011-2022 走看看