zoukankan      html  css  js  c++  java
  • 二分图匹配与树链剖分

    前置芝士:二分图

    先介绍一下什么是二分图:

    二分图又称作二部图,是图论中的一种特殊模型。 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。

    ——百度百科

    有点难懂?就是说把一个图中的点分成两部分,每一部分中的点内两两没有连边,分开之后的图就叫二分图。

    如图:


    上主菜:二分图匹配

    概念:给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。


    接下来就是如何匹配了——匈牙利算法(本蒟蒻只会这个啦

    匈牙利算法简单来说其实就是一个绿与被绿的过程。

    我就不用什么增广路等专业术语了,反正考场上又不是问我们这个叫什么。

    懒得画图了,就拿百度百科那张图来吧。

    不妨设(U)中节点从上往下为(U=left{1,2,3,4,5 ight}),同时(V=left{6,7,8,9 ight})

    首先是(1)号点,找到(6)并与它完成匹配,继续是(2)号点,也有一条边连向(6),但发现(6)已经被匹配,所以就找(6)还有没有其他点可以匹配,却没有,所以就找已经与(6)匹配的点(1),(1)也被匹配了,重复以上操作,发现除了(6)没有其他点,说明(2)不能与(6)匹配,因此找到下一个点(7),与之匹配。

    然后就是不断重复以上操作,直到枚举完为止。我们其实可以发现这是一个递归的过程,所以用DFS就可以啦!

    代码因本人丑陋的码风就不贴了,网上代码满天飞,其实也可以自己想想该怎么实现。


    咱门继续下一个:

    树链剖分

    这种数据结构很适合码农来打

    当我们遇到类似树上求一条链(x-y)的点值总和时,就会聪明的进行一次预处理,然后(ans=sum[x]+sum[y]-sum[lca]-sum[fa[lca]])

    但如果有修改操作呢?这种方式就行不通了,所以只能引入一个新的数据结构:树链剖分。

    主要基操 (我基本不会的操作:将树上的修改转移到树的DFS序上

    首先维护一个数组(son[u]),表示(u)的重儿子,也就是节点数最大的那个儿子节点,同时需要(size[u],dep[u],fa[u],dfn[u],id[x]),前三个应该不用说了吧?(dfn[u])表示(u)节点在DFS序中的下标,(id[x])则是在DFS序中下标为(x)的节点。

    预处理:两遍DFS:

    第一遍DFS处理的是重儿子,为什么不一起处理呢?因为我们要保证DFS序中一个节点与它的重儿子在一起,所以要先处理重儿子数组。第二遍DFS就是处理DFS序了。代码如下:

    void dfs1(int u,int fat)
    {
    	size[u]=1;
    	for(re int v,i=hd[u];i;i=e[i].net)
    	{
    		v=e[i].v;
    		if(v==fat)continue;
    		fa[v]=u,dep[v]=dep[u]+1;
    		dfs1(v,u);
    		size[u]+=size[v];
    		if(size[v]>size[son[u]])son[u]=v;
    	}
    }
    void dfs2(int u,int fat)
    {
    	dfn[u]=++cnt,id[cnt]=u,top[u]=fat;
    	if(son[u]==0)return ;
    	dfs2(son[u],fat);//保证它与它的重儿子在一起
    	for(re int v,i=hd[u];i;i=e[i].net)
    	{
    		v=e[i].v;
    		if(v==fa[u]||v==son[u])continue;
    		dfs2(v,v);
    	}
    }
    

    然后就用线段树,树状数组等在DFS序上乱搞就行了。


    模板例题:P3384 轻重链剖分

    这题与上面的问题差不多,多了一个子树处理,稍微提示一下:一个节点与它的子树节点的DFS序靠在一起,所以可以思考一下。

    手起,码落:

    #include<bits/stdc++.h>
    #define re register
    using namespace std;
    inline int read()
    {
    	re int x=0,f=1;
    	re char ch=getchar();
    	for(;ch>'9'||ch<'0';ch=getchar())if(ch=='-')f*=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
    	return x*f;
    }
    const int N=100005;
    struct edge{int v,net;}e[N<<1];
    struct tree{int l,r,val,lazy;}t[N<<3];
    int n,m,cnt,a[N],hd[N],dfn[N],top[N],son[N],mod,dep[N],size[N],fa[N],id[N],rt;
    inline void ad(int v,int u)
    {
    	e[++cnt].v=v,e[cnt].net=hd[u],hd[u]=cnt;
    	e[++cnt].v=u,e[cnt].net=hd[v],hd[v]=cnt;
    }
    void dfs1(int u,int fat)
    {
    	size[u]=1;
    	for(re int v,i=hd[u];i;i=e[i].net)
    	{
    		v=e[i].v;
    		if(v==fat)continue;
    		fa[v]=u,dep[v]=dep[u]+1;
    		dfs1(v,u);
    		size[u]+=size[v];
    		if(size[v]>size[son[u]])son[u]=v;
    	}
    }
    void dfs2(int u,int fat)
    {
    	dfn[u]=++cnt,id[cnt]=u,top[u]=fat;
    	if(son[u]==0)return ;
    	dfs2(son[u],fat);
    	for(re int v,i=hd[u];i;i=e[i].net)
    	{
    		v=e[i].v;
    		if(v==fa[u]||v==son[u])continue;
    		dfs2(v,v);
    	}
    }
    inline void Down(int x)
    {
    	if(t[x].lazy)
    	{
    		(t[x<<1].lazy+=t[x].lazy)%=mod,(t[x<<1|1].lazy+=t[x].lazy)%=mod;
    		(t[x<<1].val+=t[x].lazy*(t[x<<1].r-t[x<<1].l+1)%mod)%=mod,(t[x<<1|1].val+=t[x].lazy*(t[x<<1|1].r-t[x<<1|1].l+1)%mod)%=mod;
    		t[x].lazy=0;
    	}
    }
    int query(int l,int r,int x)
    {
    	if(l<=t[x].l&&t[x].r<=r)return t[x].val;
    	Down(x);
    	re int sum=0;
    	if(t[x<<1].r>=l)(sum+=query(l,r,x<<1))%=mod;
    	if(t[x<<1|1].l<=r)(sum+=query(l,r,x<<1|1))%=mod;
    	return sum%mod;
    }
    void add(int l,int r,int x,int val)
    {
    	if(l<=t[x].l&&t[x].r<=r)
    	{
    		(t[x].lazy+=val)%=mod,(t[x].val+=val*(t[x].r-t[x].l+1)%mod)%=mod;
    		return ;
    	}
    	Down(x);
    	if(t[x<<1].r>=l)add(l,r,x<<1,val);
    	if(t[x<<1|1].l<=r)add(l,r,x<<1|1,val);
    	t[x].val=(t[x<<1].val+t[x<<1|1].val)%mod;
    }
    inline void query_add(int x,int y,int val)
    {
    	re int fx=top[x],fy=top[y];
    	for(;fx^fy;)
    	{
    		if(dep[fx]>=dep[fy])
    		{
    			add(dfn[fx],dfn[x],1,val);
    			x=fa[fx],fx=top[x];
    		}
    		else
    		{
    			add(dfn[fy],dfn[y],1,val);
    			y=fa[fy],fy=top[y];
    		}
    	}
    	if(dfn[x]<dfn[y])add(dfn[x],dfn[y],1,val);
    	else add(dfn[y],dfn[x],1,val);
    }
    inline int query_sum(int x,int y)
    {
    	re int fx=top[x],fy=top[y],sum=0;
    	for(;fx^fy;)
    	{
    		if(dep[fx]>=dep[fy])
    		{
    			(sum+=query(dfn[fx],dfn[x],1))%=mod;
    			x=fa[fx],fx=top[x];
    		}
    		else
    		{
    			(sum+=query(dfn[fy],dfn[y],1))%=mod;
    			y=fa[fy],fy=top[y];
    		}
    	}
    	if(dfn[x]<dfn[y])(sum+=query(dfn[x],dfn[y],1))%=mod;
    	else (sum+=query(dfn[y],dfn[x],1))%=mod;
    	return sum;
    }
    void build(int l,int r,int x)
    {
    	t[x].l=l,t[x].r=r;
    	if(l>r)return ;
    	else if(l==r)
    	{
    		t[x].val=a[id[l]];
    		return ;
    	}
    	re int mid=(l+r)>>1;
    	build(l,mid,x<<1);
    	build(mid+1,r,x<<1|1);
    	t[x].val=(t[x<<1].val+t[x<<1|1].val)%mod;
    }
    int main()
    {
    	n=read(),m=read(),rt=read(),mod=read();
    	for(re int i=1;i<=n;i++)a[i]=read();
    	for(re int i=1;i<n;i++)ad(read(),read());
    	cnt=0,dfs1(rt,0),dfs2(rt,rt),build(1,n,1);
    	for(re int type,x,y,z,i=1;i<=m;i++)
    	{
    		type=read(),x=read();
    		if(type==1)
    		{
    			y=read(),z=read();
    			query_add(x,y,z);
    		}
    		else if(type==2)
    		{
    			y=read();
    			printf("%d
    ",query_sum(x,y));
    		}
    		else if(type==3)
    		{
    			z=read();
    			add(dfn[x],dfn[x]+size[x]-1,1,z);
    		}
    		else printf("%d
    ",query(dfn[x],dfn[x]+size[x]-1,1));
    	}
    	return 0;
    }
    
  • 相关阅读:
    data object audit
    trigger dependencies
    redo allocation latch redo copy latch
    查看TEMP 表空间usage
    oracle 查看隐藏参数
    weblogic 10 无密码启动
    lead 函数和 lag函数
    oracle latch
    查看OS 各项参数
    深度学习小贴士
  • 原文地址:https://www.cnblogs.com/jkzcr01-QAQ/p/13575489.html
Copyright © 2011-2022 走看看