• 暗的连锁


    https://loj.ac/problem/10131

    题目描述

      给出一张图,有(n)个节点和两类边,一类为主要边,一类为次要边,主要边构成图的一棵生成树,求有多少种方案可以在断掉一条主要边和一条次要边后与不再连通。

    思路

      我们把图看做一棵树,加上一些非树边。我们考虑如果存在一条(x、y)的非树边,那么树上(x、y)路径上的点一定要斩断这条非树边。所以对于每条非树边((x,y)),我们记为把树上(x、y)的路径覆盖了一次,由此我们可以知道,对于覆盖了(0)次的边,我们斩断它后选任意一条非树边都可以;对于覆盖了(1)次的点,我们只有一种方案;对于覆盖了(2)次及以上的点,我们无法实现不连通。

      而覆盖了几次这个内容我们可以用树上差分实现,由于边不好记录,我们先转化为点,对于((x,y)),使用树上差分,我们把(val[x]++,val[y]++,val[lca]-2)实现,最后每个点的实际值就是其子树的权值和。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N=1e5+10;
    
    int nxt[N<<1],to[N<<1],from[N<<1],tot,head[N];
    void add_edge(int x,int y)
    {
    	nxt[++tot]=head[x];
    	head[x]=tot;
    	to[tot]=y;from[tot]=x;
    }
    
    int f[N][22],dep[N];
    void deal_first(int u,int fa)
    {
    	dep[u]=dep[fa]+1;
    	for(int i=0;i<20;i++)
    		f[u][i+1]=f[f[u][i]][i];
    	for(int i=head[u];i;i=nxt[i])
    	{
    		int v=to[i];
    		if(v==fa)continue ;
    		f[v][0]=u;
    		deal_first(v,u);
    	}
    }
    int LCA(int x,int y)
    {
    	if(dep[x]<dep[y])swap(x,y);
    	for(int i=20;i>=0;i--)
    	{
    		if(dep[f[x][i]]>=dep[y])x=f[x][i];
    		if(x==y)return y;
    	}
    	for(int i=20;i>=0;i--)
    		if(f[x][i]!=f[y][i])
    		{
    			x=f[x][i];
    			y=f[y][i];
    		}
    	return f[x][0];
    }
    int sum[N],val[N];
    void dfs(int u,int fa)
    {
    	sum[u]=val[u];
    	for(int i=head[u];i;i=nxt[i])
    	{
    		int v=to[i];
    		if(v==fa)continue ;
    		dfs(v,u);
    		sum[u]+=sum[v];
    	}
    }
    
    int read()
    {
    	int res=0,w=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
    	return res*w;
    }
    void write(int x)
    {
    	if(x<0){putchar('-');x=-x;}
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    } 
    void writeln(int x)
    {
    	write(x);
    	putchar('
    ');
    }
    
    int main() 
    {
    	int n=read(),m=read();
    	for(int i=1;i<n;i++)
    	{
    		int x=read(),y=read();
    		add_edge(x,y);add_edge(y,x);
    	}
    	deal_first(1,0);
    	for(int i=1;i<=m;i++)
    	{
    		int x=read(),y=read();
    		int lca=LCA(x,y);
    		val[x]++;val[y]++;
    		val[lca]-=2;
    	}
    	dfs(1,0);
    	int ans=0;
    	for(int i=2;i<=n;i++)
    		if(sum[i]==1)ans++;
    		else if(sum[i]==0)ans+=m;
    	writeln(ans);
    	return 0;
    }
    
    
  • 相关阅读:
    导热硅胶片的特性
    电子器件热设计估算技巧 1
    什么是热阻
    功率器件的热设计
    ESP8266EX 电路设计
    STM8S005 ADC采集 5位共阴数码管显示
    PCB设计-Allegro软件入门系列第九讲-Class分类和Subclass应用
    STM32 滴答时钟 SysTick 的使用 STM32F103C8T6
    SPI 串行Flash闪存W25Q128FV 的使用(STM32F407)_基础篇
    如何居中一个元素
  • 原文地址:https://www.cnblogs.com/fangbozhen/p/11788407.html
Copyright © 2020-2023  润新知