zoukankan      html  css  js  c++  java
  • 泡芙

    题目链接

    如果不是有题解一辈子都调不出来

    tarjan

    题目中说“这条路就不能再走了”所以是不能缩点嘛……?

    看这张图

    会发现从环里的点出发走一圈正好是可以走回来的!可以缩点!

    tips:边不能重复走可以缩点,点不能重复走不能缩点

    注意实际处理与一般情况稍有区别,

    在这张图中,一般情况下会作为一个强连通分量,但是因为边不能重复,所以它们其实不能绕一圈绕回来,怎么办?

    特判,不直接向父亲节点转移,因为从父亲到儿子这条边已经走过了,再转移就走重了

    如果有重边呢(原题中并没有说明有没有重边自环)

    明明是一个强连通分量但是却不会缩点

    可以改为特判边有没有走过,也可以当成多个点处理,不影响

    lca

    缩完点是dag!爆搜!,,,然而t了

    看这张图,这是dag然而不是树

    同样是有向无环,但是dag图中一个点可以有多个前继,而树只能有一个爸爸

    但是如果是无向图呢?

    这种情况就会作为一个强连通分量被缩成一个点

    在树上求两点之间的路径,边不能重复走,相当于求最近公共祖先

    边权

    在tarjan后面重新建图的部分需要遍历所有边,把一个强连通分量的边权直接作为点权加上,不同强联通分量的边权作为新建的边的边权,正反建两次,因为边不会重走,所以不会加重

    lca预处理时dis[u][i]表示u到u的2i个祖先的路径中所有边权,点权的和,不包括u的2i个祖先的点权

    dis[u][i]与fa处理思路类似,即dis[fa[u][i-1]][i-1]+dis[u][i-1]

    因为dis不包括路径终点(祖宗)的点权,所以要找到lca后要把lca的点权加上

    代码

    #include<bits/stdc++.h>
    using namespace std;
    int cnt=0,head[600100],uu[600100],vv[600010],zz[600100],dfn[601000],low[600100],t=0,sum[600010],dis[600010][21],in[600010],dep[600100],fa[600010][21],color[600100],colornum=0,stac=0,sta[600010];
    struct node{
    	int w,nxt,to;
    }road[600100];
    void build(int u,int v,int z)
    {
    	road[++cnt].w=z;
    	road[cnt].nxt=head[u];
    	road[cnt].to=v;
    	head[u]=cnt;
    }
    void tarjan(int f,int u)
    {
    	dfn[u]=low[u]=++t;
    	in[u]=1,sta[++stac]=u;
    	for(int i=head[u];i;i=road[i].nxt)
    	{
    		int v=road[i].to;
    		if(v==f) continue;
    		if(!dfn[v]) 
    		{
    			tarjan(u,v);
    			low[u]=min(low[u],low[v]);
    		}
    		else if(in[v]) low[u]=min(low[u],dfn[v]);
    	}
    	if(low[u]==dfn[u])
    	{
    		color[u]=++colornum;
    		in[u]=0;
    		while(sta[stac]!=u)
    		{
    			color[sta[stac]]=colornum;
    			in[sta[stac]]=0;
    			stac--;
    		}
    		stac--;
    	}
    }
    void dfs(int f,int u,int z)
    {
    	dep[u]=dep[f]+1;
    	fa[u][0]=f;
    	dis[u][0]=sum[u]+z;
    	for(int i=1;i<=20;i++)
    	{
    		fa[u][i]=fa[fa[u][i-1]][i-1];
    		dis[u][i]=dis[fa[u][i-1]][i-1]+dis[u][i-1];
    	}
    	for(int i=head[u];i;i=road[i].nxt)
    	{
    		int v=road[i].to;
    		if(!dep[v]&&v!=f) dfs(u,v,road[i].w);
    	}
    }
    int lca(int x,int y)
    {
    	int ans=0;
    	if(dep[x]>dep[y]) swap(x,y);
    	for(int i=20;i>=0;i--)
    		if(dep[fa[y][i]]>=dep[x]) ans+=dis[y][i],y=fa[y][i];
    	if(x==y) return ans+sum[x];//QAQ
    	for(int i=20;i>=0;i--)
    		if(fa[y][i]!=fa[x][i]) ans+=dis[x][i]+dis[y][i],x=fa[x][i],y=fa[y][i];
    	if(fa[x][0]==fa[y][0]) return ans+sum[fa[x][0]]+dis[x][0]+dis[y][0];
    	else return 0;
    }
    int main()
    {
    	int n,m;
    	cin>>n>>m;
    	for(int i=1;i<=m;i++)
    	{
    		cin>>uu[i]>>vv[i]>>zz[i];
    		build(uu[i],vv[i],zz[i]);
    		build(vv[i],uu[i],zz[i]);
    	}
    	for(int i=1;i<=n;i++)
    	{
    		if(!dfn[i]) tarjan(0,i);
    	}
    	memset(head,0,sizeof(head));
    	cnt=0;
    	for(int i=1;i<=m;i++)
    	{
    		if(color[uu[i]]!=color[vv[i]])
    		{
    			build(color[uu[i]],color[vv[i]],zz[i]);
    			build(color[vv[i]],color[uu[i]],zz[i]);
    		}
    		else sum[color[uu[i]]]+=zz[i];//缩点的时候如何处理边权 
    	}
    	for(int i=1;i<=colornum;i++)
    	{
    		if(!fa[i][0]) dfs(0,i,0);
    	}
    	int q,s,t;
    	cin>>q;
    	for(int i=1;i<=q;i++)
    	{
    		cin>>s>>t;
    		int lcan=lca(color[s],color[t]);
    		if(lcan>0) cout<<"YES"<<"
    ";
    		else cout<<"NO"<<"
    ";
    	}
    	return 0;
     } 
    
  • 相关阅读:
    [矩阵快速幂专题]
    [hdoj6415 Rikka with Nash Equilibrium][dp]
    [codeforces][dp]
    [2019年湘潭大学程序设计竞赛(重现赛)H chat][背包dp]
    [一道区间dp][String painter]
    [hdoj4578][多延迟标记的线段树]
    [cf1138BCircus][枚举,列等式]
    [Assign the task][dfs序+线段树]
    Codeforces round 419 div2 补题 CF 816 A-E
    Educational Codeforces Round 23 A-F 补题
  • 原文地址:https://www.cnblogs.com/qwq-/p/13660825.html
Copyright © 2011-2022 走看看