#模板整理

是一些想要会打的模板
持更ovo

高精度

inline void Init(int a[])//输入 
{
	string s;
	cin>>s;
	int len=s.length();
	for(re int i=0;i<len;i++)
	{
		int j=(len-i+3)/4;
		a[j]=a[j]*10+s[i]-'0';
	}
	a[0]=(len+3)/4;
}

                              
inline void Print(int a[])//输出 
{
	cout<<a[a[0]];
	for(re int i=a[0]-1;i>0;i--)
	for(re int j=base/10;j>0;j/=10)
		cout<<a[i]/j%10;
}

                                        
inline int Comp(int a[],int b[])//比较大小 相等输出0,a>b输出1,a<b输出-1 
{
	if(a[0]>b[0]) return 1;
	if(a[0]<b[0]) return -1;
	for(re int i=a[0];i>=1;i--)
		if(a[i]>b[i])
			return 1;
		else if(a[i]<b[i])
			return -1;
	return 0;
}
                           
                           
inline void Div(int a[],int k)//高精除以低精 
{
	int t=0;
	for(re int i=a[0];i>=1;i--)
	{
		t=t*base+a[i];
		a[i]=t/k;
		t%=k;
	}
	while(a[a[0]]==0&&a[0]>0)
		a[0]--;
}
      
      
inline void Minus(int a[],int b[])//高精减 
{
	for(re int i=1;i<=a[0];i++)
	{
		a[i]-=b[i];
		if(a[i]<0)
		{
			a[i+1]--;
			a[i]+=base;
		}
		while(a[a[0]]==0&&a[0]>0)
			a[0]--;
	}
}

      
inline void MulHigh(int a[],int b[])//高精乘高精 
{
	memset(c,0,sizeof(c));
	for(re int i=1;i<=a[0];i++)
	  for(re int j=1;j<=b[0];j++)
	  {
	   	  c[i+j-1]+=a[i]*b[j];
	   	  c[i+j]+=c[i+j-1]/base;
	   	  c[i+j-1]%=base;
	  }
	c[0]=a[0]+b[0];
	while(c[c[0]]==0&&c[0]>0)
	  	c[0]--;
	for(re int i=0;i<=c[0];i++)
		a[i]=c[i];
}
                               
                               
inline void MulLow(int a[],int k)//高精乘低精 
{
	for(re int i=1;i<=a[0];i++)
		a[i]*=k;
	for(re int i=1;i<=a[0];i++)
	{
		a[i+1]+=a[i]/base;
		a[i]%=base;
	}
	while(a[a[0]+1]>0)
	{
		a[0]++;
		a[a[0]+1]=a[a[0]]/base;
		a[a[0]]%=base;
	}
}

同余定理(扩展欧几里得求特解)

void Exgcd(int a,int b,int &d,int &x,int &y)
{
	if(b==0)
	{
		d=a;
		x=c/a;
		y=0;
	}
	else
	{
		int x1,y1;
		Exgcd(b,a%b,d,x1,y1);
		x=y1;
		y=x1-a/b*y1;
	}
}

若需求(1sim b)范围内的最小正整数解,则

x=(x%d+d)%d;

快速幂

base=b;
	while(p)
	{
		if(p&1)
			ans=(ans%k*base%k)%k;
		p>>=1;
		base=(base%k*base%k)%k;
	}

线性筛(欧拉筛)

for(int i=2;i<=n;i++)
	{
		if(!v[i])
		{
			v[i]=i;
			p[++total]=i;
		}
		for(int j=1;j<=total;j++)
		{
			if(p[j]>v[i]||p[j]*i>n) break;
				v[i*p[j]]=p[j];
		}
	}

埃氏筛

	for(int i=2;i<=n;i++)
	{
		if(v[i]) continue;
		for(int j=i;j*i<=n;j++)
			v[i*j]=1;
	}

Dijsktra:

priority_queue< pair<int,int> >q;
inline void DJ()
{
	memset(dis1,INF,sizeof(dis1));
	memset(dis2,INF,sizeof(dis2));
	dis1[1]=0;
	q.push(make_pair(0,1));
	while(!q.empty())
	{
		int x=q.top().second,dis=q.top().first;
		q.pop(),dis=-dis;
		if(dis>dis2[x]) continue;
		for(int i=fst[x];i;i=e[i].nxt)
		{
			int y=e[i].to,z=e[i].w;
			if(dis1[y]>dis+z)
				dis2[y]=dis1[y],
				dis1[y]=dis+z,
				q.push(make_pair(-dis1[y],y));
			if(dis+z<dis2[y]&&dis+z>dis1[y])
				dis2[y]=dis+z,
				q.push(make_pair(-dis2[y],y));
		}
	}
}

SPFA:

inline void SPFA()
{
	memset(dis,INF,sizeof(dis));
	dis[1]=0,vst[1]=true,q.push(1);
	while(!q.empty())
	{
		int i=q.front();
		for(int k=fst[i];k;k=e[k].nxt)
		{
			int j=e[k].to;
			if(dis[j]>dis[i]+e[k].v)
			{
				dis[j]=dis[i]+e[k].v;
				if(!vst[j])
				{
					q.push(j);
					vst[j]=true;
				}
			}
			
		}
		vst[i]=false;
		q.pop();
	}
}

DFS_SPFA:

inline bool SPFA(int x)
{
	v[x]=1;
	for(int i=fst[x];i;i=e[i].nxt)
	{
		int y=e[i].to,z=e[i].w;
		if(dis[y]>dis[x]+z)
		{
			dis[y]=dis[x]+z;
			if(v[y])
				return 1;
			else if(SPFA(y))
				return 1;
		}
	}
	v[x]=0;
	return 0;
}

记录入队次数のSPFA:

inline bool SPFA()
{
	memset(d,INF,sizeof(d));
	memset(v,0,sizeof(v));
	memset(cnt,0,sizeof(cnt));
	d[s]=0; 
	q.push(s);
	v[s]=1;
	while(!q.empty())
	{
		int x=q.front();q.pop();
		v[x]=0;
		o[x]=1;
		for(int i=fst[x];i;i=e[i].nxt)
		{
			int y=e[i].to,z=e[i].w;
			if(d[y]>d[x]+z)
			{
				d[y]=d[x]+z;
				if(!v[y])
				{
				    if(++cnt[y]>=n)
					return true;
					q.push(y);
					v[y]=1;
				}
			}
		}
	}
	return false;  
}

线段树基操

const int N=1e5+7; 
struct SegmentTree
{
	int l,r;
	long long sum,add;
	#define l(x) tree[x].l
	#define r(x) tree[x].r
	#define sum(x) tree[x].sum
	#define add(x) tree[x].add
}tree[N<<2];
int n,m;

void build(int p,int l,int r)
{
	l(p)=l,r(p)=r;
	if(l==r)
	{
		int h;
		read(h);
		sum(p)=h;
		return ;
	}
	int mid=(l(p)+r(p))>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
	sum(p)=sum(p<<1)+sum(p<<1|1);
} 

void spread(int p)
{
	if(add(p))
	{
		sum(p<<1)+=add(p)*(r(p<<1)-l(p<<1)+1);
		sum(p<<1|1)+=add(p)*(r(p<<1|1)-l(p<<1|1)+1);
		add(p<<1)+=add(p);
		add(p<<1|1)+=add(p);
		add(p)=0;
	}
}

void change(int p,int l,int r,int d)
{
	if(l<=l(p)&&r(p)<=r)
	{
		sum(p)+=(long long)d*(r(p)-l(p)+1);
		add(p)+=d;
		return ;
	}
	spread(p);
	int mid=(l(p)+r(p))>>1;
	if(l<=mid) change(p<<1,l,r,d);
	if(mid<r) change(p<<1|1,l,r,d);
	sum(p)=sum(p<<1)+sum(p<<1|1);
}

long long ask(int p,int l,int r)
{
	if(l<=l(p)&&r(p)<=r) return sum(p);
	spread(p);
	int mid=(l(p)+r(p))>>1;
	long long val=0;
	if(l<=mid) val+=ask(p<<1,l,r);
	if(mid<r) val+=ask(p<<1|1,l,r);
	return val; 
}

AC自动机

const int N=7e5+7;
int tree[N][26];
int cnt[N];
int f[N];
int T,n,tot;
string s,w;

inline void Clear()
{
	memset(tree,0,sizeof(tree));
	memset(cnt,0,sizeof(cnt));
	memset(f,0,sizeof(f));
	tot=0;
}

inline void insert(string s)
{
	int root=0;
	for(int i=0;i<s.size();i++)
	{
		int nxt=s[i]-'a';
		if(!tree[root][nxt])
			tree[root][nxt]=++tot;
		root=tree[root][nxt];
	}
	cnt[root]++;//当前节点单词数+1 
}

inline void GetFail()
{
	queue<int>q;
	for(int i=0;i<26;i++)
		if(tree[0][i])
		{
			q.push(tree[0][i]);
			f[tree[0][i]]=0;
		}
	while(!q.empty())
	{
		int now=q.front();
		q.pop();
		for(int i=0;i<26;i++)
		{
			if(tree[now][i])
			{
				f[tree[now][i]]=tree[f[now]][i];
				q.push(tree[now][i]);
			}
			else
				tree[now][i]=tree[f[now]][i];
		}
	}
}

inline int query(string s)
{
	int now=0,smx=0;
	for(int i=0;i<s.size();i++)
	{
		now=tree[now][s[i]-'a'];
		for(int j=now;cnt[j]!=-1;j=f[j])
		{
			smx+=cnt[j];
			cnt[j]=-1;
		}
	}
	return smx;
}

KMP

const int N=1e6+7;
char s1[N],s2[N];
int nxt[N];
int l1,l2;

int main()
{
	cin>>s1+1;
	cin>>s2+1;
	l1=strlen(s1+1);
	l2=strlen(s2+1);
	for(int i=2,j=0;i<=l2;i++)
	{
		while(j&&s2[i]!=s2[j+1]) j=nxt[j];
		if(s2[j+1]==s2[i]) j++;
		nxt[i]=j;
	}
	for(int i=1,j=0;i<=l1;i++)
	{
		while(j>0&&s2[j+1]!=s1[i]) j=nxt[j];
		if(s2[j+1]==s1[i]) j++;
		if(j==l2)
			printf("%d
",i-l2+1),j=nxt[j];
	}
	for(int i=1;i<=l2;i++)
		printf("%d ",nxt[i]);
	return 0;
}

Splay

const int N=1e5+7,INF=23140414;
int n,op,x;
int root,tot;
struct Node
{
	int v,fa,ch[2],size,recy;
}e[N];

inline int i(int x)
{
	return e[e[x].fa].ch[1]==x;
}

inline void connect(int x,int f,int son)
{
	e[x].fa=f;
	e[f].ch[son]=x;
}

inline void update(int x)
{
	e[x].size=e[x].recy;
	e[x].size+=e[e[x].ch[0]].size;
	e[x].size+=e[e[x].ch[1]].size;
}

inline void rotate(int x)
{
	int f=e[x].fa;
	int g_f=e[f].fa;
	int locate_f=i(f);
	int locate_x=i(x);
	int v=e[x].ch[locate_x^1];//旋后u重复儿子,需放到f的空儿子 
	connect(v,f,locate_x);
	connect(f,x,locate_x^1);
	connect(x,g_f,locate_f);
	update(f);//注意顺序 
	update(x);
}

inline void Splay(int x,int goal)
{
	while(e[x].fa!=goal)
	{
		int y=e[x].fa;
		int z=e[y].fa;
		if(z!=goal)
			(e[y].ch[0]==x)^(e[z].ch[0]==y)?rotate(x):rotate(y);
		rotate(x);
	}
	if(goal==0)
		root=x;
}

inline void Insert(int x)
{
	int u=root,f=0;
	while(u&&e[u].v!=x) f=u,u=e[u].ch[x>e[u].v];
	if(u)
		e[u].recy++;
	else
	{
		u=++tot;
		if(f)
			e[f].ch[x>e[f].v]=u;
		e[tot].ch[0]=e[tot].ch[1]=0;
		e[tot].fa=f,e[tot].v=x,e[tot].size=e[tot].recy=1;
	}
	Splay(u,0);
}

inline void Get_Rank(int x)
{
	int u=root;
	if(!u) return;
	while(e[u].ch[x>e[u].v]&&x!=e[u].v)
		u=e[u].ch[x>e[u].v];
	Splay(u,0);
}

inline int Get_Val(int x)
{
	int u=root;
	if(e[u].size<x)
		return false;
	while(1)
	{
		int y=e[u].ch[0];
		if(x>e[y].size+e[u].recy)
			x-=e[y].size+e[u].recy,u=e[u].ch[1];
		else
			if(e[y].size>=x) u=y;
		else
			return e[u].v;
	}
}

inline int Get_Next(int x,bool op)
{
	Get_Rank(x);
	int u=root;
	if((e[u].v>x&&op)||(e[u].v<x&&!op)) return u;
	u=e[u].ch[op];
	while(e[u].ch[op^1]) u=e[u].ch[op^1];
	return u;
}

inline void Delete(int x)
{
    int last=Get_Next(x,0);
    int next=Get_Next(x,1);
    Splay(last,0);
    Splay(next,last);
    int del=e[next].ch[0];
    if(e[del].recy>1)
    	e[del].recy--,Splay(del,0);
    else
    	e[next].ch[0]=0;
}

Treap

const int N=1e5+7,INF=0x7fffffff;
struct Treap
{
	int val,dat;
	int l,r;
	int size,cnt;
	#define val(x) t[x].val
	#define dat(x) t[x].dat
	#define l(x) t[x].l
	#define r(x) t[x].r
	#define size(x) t[x].size
	#define cnt(x) t[x].cnt
}t[N];
int n,root,tot;

int New(int val)
{
	val(++tot)=val;
	dat(tot)=rand();
	cnt(tot)=size(tot)=1;
	return tot;
}

inline void update(int p)
{
	size(p)=size(l(p))+size(r(p))+cnt(p);
}

inline void Build()
{
	New(-INF),New(INF);
	root=1;
	r(root)=2;
	update(root);
}

int Get_Rank(int p,int val)
{
	if(p==0) return 0;
	if(val(p)==val) return size(l(p))+1;
	if(val<val(p)) return Get_Rank(l(p),val);
	return Get_Rank(r(p),val)+size(l(p))+cnt(p);
}

int Get_Val(int p,int rank)
{
	if(p==0) return INF;
	if(size(l(p))>=rank) return Get_Val(l(p),rank);	
	if(size(l(p))+cnt(p)>=rank) return val(p);
	return Get_Val(r(p),rank-size(l(p))-cnt(p));
}

inline void zig(int &p)
{
	int q=l(p);
	l(p)=r(q),r(q)=p;
	p=q;
	update(r(p)),update(p);
}

inline void zag(int &p)
{
	int q=r(p);
	r(p)=l(q),l(q)=p;
	p=q;
	update(l(p)),update(p);
}

void Insert(int &p,int val)
{
	if(p==0)
	{
		p=New(val);
		return ;
	}
	if(val(p)==val)
	{
		cnt(p)++;
		update(p);
		return ;
	}
	if(val<val(p))
	{
		Insert(l(p),val);
		if(dat(l(p))>dat(p))
			zig(p);
	}
	else
	{
		Insert(r(p),val);
		if(dat(r(p))>dat(p))
			zag(p);
	}
	update(p);
}

int Get_Pre(int val)
{
	int ans=1;
	int p=root;
	while(p)
	{
		if(val(p)==val)
		{
			if(l(p)>0)
			{
				p=l(p);
				while(r(p)) p=r(p);
				ans=p;
			}
			break;
		}
		if(val(p)<val&&val(p)>val(ans)) ans=p;
		p=val<val(p)?l(p):r(p);
	}
	return val(ans);
}

int Get_Next(int val)
{
	int ans=2;
	int p=root;
	while(p)
	{
		if(val(p)==val)
		{
			if(r(p)>0)
			{
				p=r(p);
				while(l(p)) p=l(p);
				ans=p;
			}
			break;
		}
		if(val(p)>val&&val(p)<val(ans)) ans=p;
		p=val<val(p)?l(p):r(p);
	}
	return val(ans);
}

void Remove(int &p,int val)
{
	if(p==0) return ;
	if(val(p)==val)
	{
		if(cnt(p)>1)
		{
			cnt(p)--;
			update(p);
			return ;
		}
		if(l(p)||r(p))
		{
			if(r(p)==0||dat(l(p))>dat(r(p)))
				zig(p),Remove(r(p),val);
			else
				zag(p),Remove(l(p),val);
			update(p);
		}
		else
			p=0;
		return ;
	}
	val<val(p)?Remove(l(p),val):Remove(r(p),val);
	update(p);
}

树剖

const int N=1e5+7;
struct rec{int nxt,to;}e[N<<1];
int fst[N<<1];
int n,m,op;
int w[N];
//w:点权 
ll sum[N<<2],lz[N<<2];
int size[N],son[N],fa[N],dep[N];
//size:子树的大小
//son:重儿子
//fa:父节点
//dep:深度 
int top[N],rev[N],seg[N<<1];
//top:所在重链的起点
//seg:节点在线段树上的位置  seg[x]=y:x在线段树上的位置为y 
//rev:线段树上的位置对应的节点  rev[x]=y:线段树上第x个位置为y节点 
int t1=0,t2=0;
//t1为第一次建边时的序,t2为建线段树时的序 

void read(int &x)
{
	char ch=getchar();x=0;int f=1;
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	x*=f;
}

void add(int u,int v)
{
	e[++t1].nxt=fst[u];
	e[t1].to=v;
	fst[u]=t1;
}
//以下为树剖操作 
void dfs1(int x,int f)//求出dep,fa,size,son 
{
	dep[x]=dep[f]+1;
	fa[x]=f;
	size[x]=1;
	for(int i=fst[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		if(y==f) continue;
		dfs1(y,x);
		size[x]+=size[y];
		if(size[y]>size[son[x]])
		//如果子节点y的大小大于当前重儿子的大小,更新x的重儿子 
			son[x]=y;
	}
}

void dfs2(int u,int f)//求出rev,seg,top 
{
	if(son[u])
	//如果u有重儿子,加入线段树中 
	//能够保证重链中的节点的dfs2序是连续的 
	{
		int v=son[u];
		top[v]=top[u];//更新top,重儿子的top和自身top一定是同一个值 
		seg[v]=++t2;//v对应线段树上第++t2个位置
		rev[t2]=v;//线段树上第t2个位置为v
		dfs2(v,u);
	}
	for(int i=fst[u];i;i=e[i].nxt)
	{
		int v=e[i].to;
		if(!top[v]&&v!=f)//top[v]==0,说明它不在u所在重链中,是个轻儿子
		{
			top[v]=v;//其所在重链的起点为自身 
			seg[v]=++t2;
			rev[t2]=v;
			dfs2(v,u);
		} 
	}
}
//以上为树剖操作
//以下为线段树操作 
void build(int k,int l,int r)
{
	if(l==r)
	{
		sum[k]=w[rev[l]];//rev在这儿起到作用
		return; 
	}
	int m=(l+r)>>1;
	build(k<<1,l,m);
	build(k<<1|1,m+1,r);
	sum[k]=sum[k<<1]+sum[k<<1|1];
}

void add_v(int k,int l,int r,ll v)
{
	lz[k]+=v;
	sum[k]+=(ll)(r-l+1)*v; 
}

void push_down(int k,int l,int r)
{
	if(lz[k])
	{
		int m=(l+r)>>1;
		add_v(k<<1,l,m,lz[k]);
		add_v(k<<1|1,m+1,r,lz[k]);
	}
	lz[k]=0;
}

void change(int k,int l,int r,int x,int y,int v)
{
	if(x<=l&&r<=y)
	{
		add_v(k,l,r,v);
		return ;
	}
	int m=(l+r)>>1;
	push_down(k,l,r);
	if(m>=x) change(k<<1,l,m,x,y,v);
	if(m<y) change(k<<1|1,m+1,r,x,y,v);
	sum[k]=sum[k<<1]+sum[k<<1|1];
}

ll query(int k,int l,int r,int x,int y)
{
	if(x<=l&&r<=y) return sum[k];
	int m=(l+r)>>1;
	push_down(k,l,r);
	ll rs=0;
	if(m>=x) rs=query(k<<1,l,m,x,y);
	if(m<y) rs+=query(k<<1|1,m+1,r,x,y);
	return rs;
}
//以上为线段树操作
//以下为树剖询问 
ll ask(int x,int y)
{
	int fx=top[x],fy=top[y];
	ll rs=0;
	while(fx!=fy)//不在一条重链中 
	{
		if(dep[fx]<dep[fy]) swap(x,y),swap(fx,fy);//使x为两者中深度更深的一个 
		rs+=query(1,1,t2,seg[fx],seg[x]);//rs加上x到所在重链顶部的值 
		x=fa[fx],fx=top[x];//再使x为重链顶的父亲; 
	}
	if(dep[x]>dep[y]) swap(x,y);
	rs+=query(1,1,t2,seg[x],seg[y]);//若在一条重链中,因为重链是连续的区间,故直接询问区间值即可 
	return rs; 
}
//以上为树剖询问 
void Read()
{
	read(n),read(m);
	memset(son,0,sizeof(son));
	for(int i=1;i<=n;i++)
		read(w[i]);
	for(int i=1,x,y;i<n;i++)
	{
		read(x),read(y);
		add(x,y),add(y,x);
	}
}

void Work()
{
	t2=top[1]=rev[1]=seg[1]=1;
	dfs1(1,0);
	dfs2(1,0);
	build(1,1,t2);
}

void Answer()
{
	int x,y;
	while(m--)
	{
		read(op),read(x);
		if(op==3)
			printf("%lld
",ask(1,x));
		else
		{
			read(y);
			if(op==1)
				change(1,1,t2,seg[x],seg[x],y);
			else
				change(1,1,t2,seg[x],seg[x]+size[x]-1,y);
		}
	}
}

Tarjan

割点

const int N=1e4+7;
struct rec{int to,nxt;}e[N<<1];
int fst[N],tot=0; 
bool cut[N];
int dfn[N],low[N];
int n,m,num=0;
int root;

void add(int u,int v)
{
	e[++tot].to=v;
	e[tot].nxt=fst[u];
	fst[u]=tot;
}

void Tarjan(int x)
{
	dfn[x]=low[x]=++num;
	int flag=0;
	for(int i=fst[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		if(!dfn[y])
		{
			Tarjan(y);
			low[x]=min(low[x],low[y]);
			if(low[y]>=dfn[x])
			{
				flag++;
				if(x!=root||flag>1)
					cut[x]=true; 
			} 
				
		}
		else low[x]=min(low[x],dfn[y]);
	}
}

割边

const int N=1e4+7;
struct rec{int to,nxt;}e[N<<1];
int fst[N],tot=1;
//跟平常书写习惯不同,tot要赋初值为1 
bool bridge[N<<1];
int dfn[N],low[N];
int n,m,num=0;

void add(int u,int v)
{
	e[++tot].to=v;
	e[tot].nxt=fst[u];
	fst[u]=tot;
}

void Tarjan(int x,int in_edge)
{
	dfn[x]=low[x]=++num;
	for(int i=fst[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		if(!dfn[y])
		{
			Tarjan(y,i);
			low[x]=min(low[x],low[y]);
			if(low[y]>dfn[x])
				bridge[i]=bridge[i^1]=1;
		}
		else if(i!=(in_edge^1))
			low[x]=min(low[x],dfn[y]);
	}
}

e-DCC的缩点

const int N=1e4+7;
struct rec{int to,nxt;}e[N<<1];
struct recc{int to,nxt;}ec[N<<1];
int fst[N],tot=1;
int fstc[N],totc=1;
bool bridge[N<<1];
int dfn[N],low[N];
int n,m,num=0;
int c[N],dcc; 

void add(int u,int v)
{
	e[++tot].to=v;
	e[tot].nxt=fst[u];
	fst[u]=tot;
}

void add_c(int u,int v)
{
	e[++totc].to=v;
	e[totc].nxt=fstc[u];
	fstc[u]=totc;
}

void Tarjan(int x,int in_edge)
{
	dfn[x]=low[x]=++num;
	for(int i=fst[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		if(!dfn[y])
		{
			Tarjan(y,i);
			low[x]=min(low[x],low[y]);
			if(low[y]>dfn[x])
				bridge[i]=bridge[i^1]=1;
		}
		else if(i!=(in_edge^1))
			low[x]=min(low[x],dfn[y]);
	}
}

void dfs(int x)
{
	c[x]=dcc;
	for(int i=fst[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		if(c[y]||bridge[i]) continue;
		dfs(y);
	}
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1,x,y;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	for(int i=1;i<=n;i++)
		if(!dfn[i]) Tarjan(i,0);
	for(int i=1;i<=n;i++)
		if(!c[i])
		{
			++dcc;
			dfs(i);
		}
	for(int i=2;i<=tot;i++)
	{
		int x=e[i^1].to,y=e[i].to;
		if(c[x]==c[y]) continue;
		add_c(c[x],c[y]);
	}
	printf("缩点之后的森林,点数%d,边数%d(可能有重边)
",dcc,totc/2);
	for(int i=2;i<totc;i+=2)
		printf("%d %d
",ec[i^1].to,ec[i].to);
	return 0;
}

v-DCC的缩点

const int N=1e4+7;
struct rec{int to,nxt;}e[N<<1];
int fst[N],tot=0; 
bool cut[N];
int dfn[N],low[N];
int n,m,num=0;
int root;
int stac[N],top=0;
vector<int>dcc[N];
int cnt;
int new_id[N];

void add(int u,int v)
{
	e[++tot].to=v;
	e[tot].nxt=fst[u];
	fst[u]=tot;
}

void Tarjan(int x)
{
	dfn[x]=low[x]=++num;
	stac[++top]=x;
	if(x==root&&fst[x]==0)
	{
		dcc[++cnt].push_back(x);
		return ; 
	} 
	int flag=0;
	for(int i=fst[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		if(!dfn[y])
		{
			Tarjan(y);
			low[x]=min(low[x],low[y]);
			if(low[y]>=dfn[x])
			{
				flag++;
				if(x!=root||flag>1)
					cut[x]=true; 
				cnt++;
				int z;
				do
				{
					z=stac[top--];
					dcc[cnt].push_back(z);
				}while(z!=y);
				dcc[cnt].push_back(x);
			} 
		}
		else low[x]=min(low[x],dfn[y]);
	}
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1,x,y;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		if(x==y) continue;
		add(x,y);
		add(y,x);
	}
	for(int i=1;i<=n;i++)
		if(!dfn[i]) root=i,Tarjan(i);
	//给每个割点一个新的编号(编号从cnt+1开始) 
	num=cnt;
	for(int i=1;i<=n;i++)
		if(cut[i]) new_id[i]=++num;
	//建新图,从每个v-DCC到它包含的所有割点连边
	tc=1;
	for(int i=1;i<=cnt;i++)
	for(int j=0;i<dcc[i].size();j++)
	{
		int x=dcc[i][j];
		if(cut[x])
		{
			add_c(i,new_id[x]);
			add_c(new_id[x],i);
		}
		else c[x]=i;//除割点外,其他点仅属于1个v-DCC 
	}
	/*输出不想写了*/
	return 0;
}

边连通分量

const int N=1e4+7;
struct rec{int to,nxt;}e[N<<1];
int fst[N],tot=1;
bool bridge[N<<1];
int dfn[N],low[N];
int n,m,num=0;
int c[N],dcc; 

void add(int u,int v)
{
	e[++tot].to=v;
	e[tot].nxt=fst[u];
	fst[u]=tot;
}

void Tarjan(int x,int in_edge)
{
	dfn[x]=low[x]=++num;
	for(int i=fst[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		if(!dfn[y])
		{
			Tarjan(y,i);
			low[x]=min(low[x],low[y]);
			if(low[y]>dfn[x])
				bridge[i]=bridge[i^1]=1;
		}
		else if(i!=(in_edge^1))
			low[x]=min(low[x],dfn[y]);
	}
}

void dfs(int x)
{
	c[x]=dcc;
	for(int i=fst[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		if(c[y]||bridge[i]) continue;
		dfs(y);
	}
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1,x,y;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	for(int i=1;i<=n;i++)
		if(!dfn[i]) Tarjan(i,0);
	for(int i=1;i<=n;i++)
		if(!c[i])
		{
			++dcc;
			dfs(i);
		}
	printf("There are %d e-DCCs.
",dcc);
	for(int i=1;i<=n;i;++)
		printf("%d belongs to DCC %d.
",i,c[i]);
	return 0;
}

点连通分量

const int N=1e4+7;
struct rec{int to,nxt;}e[N<<1];
int fst[N],tot=0; 
bool cut[N];
int dfn[N],low[N];
int n,m,num=0;
int root;
int stac[N],top=0;
vector<int>dcc[N];
int cnt;

void add(int u,int v)
{
	e[++tot].to=v;
	e[tot].nxt=fst[u];
	fst[u]=tot;
}

void Tarjan(int x)
{
	dfn[x]=low[x]=++num;
	stac[++top]=x;
	if(x==root&&fst[x]==0)//孤立的点 
	{
		dcc[++cnt].push_back(x);
		return ; 
	} 
	int flag=0;
	for(int i=fst[x];i;i=e[i].nxt)
	{
		int y=e[i].to;
		if(!dfn[y])
		{
			Tarjan(y);
			low[x]=min(low[x],low[y]);
			if(low[y]>=dfn[x])
			{
				flag++;
				if(x!=root||flag>1)
					cut[x]=true; 
				cnt++;
				int z;
				do
				{
					z=stac[top--];
					dcc[cnt].push_back(z);
				}while(z!=y);
				dcc[cnt].push_back(x);
			} 
		}
		else low[x]=min(low[x],dfn[y]);
	}
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1,x,y;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		if(x==y) continue;
		add(x,y);
		add(y,x);
	}
	for(int i=1;i<=n;i++)
		if(!dfn[i]) root=i,Tarjan(i);
	for(int i=1;i<=cnt;i++)
	{
		printf("v-DCC #%d:",i);
		for(int j=0;j<dcc[i].size();j++)
			printf(" %d",dcc[i][j]);
		puts("");
	}
	return 0;
}

二分图(最大匹配匈牙利)

bool check(int x)
{
	for(int i=1;i<=b;i++)
		if(mp[x][i])
		{
			if(vis[i])
				continue;
			vis[i]=1;
			if(!marry[i]||check(marry[i]))
			{
				marry[i]=x;
				return true;
			}
		}
	return false;
}

inline int work()
{
	int ans=0;
	for(int i=1;i<=a;i++)
	{
		memset(vis,0,sizeof(vis));
		if(check(i))
			ans++;
	}
	return ans;
}

圆方树

void Tarjan(int u)
{
    dfn[u]=low[u]=++sub,st[++top]=u;
    for(int i=fst[u];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(!dfn[v])
        {
            Tarjan(v);
            low[u]=min(low[v],low[u]);
            if(low[v]==dfn[u])
            {
                w[++cnt]=1;
                while(st[top]!=v)
                {
                    w[cnt]++;
                    add(cnt,st[top],1);
                    top--;
                }
                add(cnt,u,1);
                top--,w[cnt]++,add(v,cnt,1);
            }
        }
        else
            low[u]=min(dfn[v],low[u]);
    }
}
原文地址:https://www.cnblogs.com/Sure042/p/total.html