• #模板整理


    是一些想要会打的模板
    持更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]);
        }
    }
    
  • 相关阅读:
    【NX二次开发】难点清单
    【NX二次开发】Block UI 目录
    Open C
    【NX二次开发】缝合片体例子UF_MODL_create_sew
    【NX二次开发】拉伸的偏置方向猜想与验证
    【NX二次开发】拉伸面、拉伸封闭曲线成片体UF_MODL_create_extrusion
    【NX二次开发】创建有界平面UF_MODL_create_bplane
    【VBA】一些判断
    【VBA】日期时间
    【VBA】单元格插入图片,单元格删除图片
  • 原文地址:https://www.cnblogs.com/Sure042/p/total.html
Copyright © 2020-2023  润新知