首页 > 其他分享 >6577: 暗的连锁 LCA+树上差分

6577: 暗的连锁 LCA+树上差分

时间:2023-10-12 16:58:06浏览次数:25  
标签:6577 int 差分 Dark dep 附加 LCA 切断 节点

描述

 

 

Dark 是一张无向图,图中有 N 个节点和两类边,一类边被称为主要边,而另一类被称为附加边。Dark 有 N–1 条主要边,并且 Dark 的任意两个节点之间都存在一条只由主要边构成的路径。另外,Dark 还有 M 条附加边。

你的任务是把 Dark 斩为不连通的两部分。一开始 Dark 的附加边都处于无敌状态,你只能选择一条主要边切断。一旦你切断了一条主要边,Dark 就会进入防御模式,主要边会变为无敌的而附加边可以被切断。但是你的能力只能再切断 Dark 的一条附加边。

现在你想要知道,一共有多少种方案可以击败 Dark。注意,就算你第一步切断主要边之后就已经把 Dark 斩为两截,你也需要切断一条附加边才算击败了 Dark。

 

 

输入

 

 

第一行包含两个整数 N 和 M;

之后 N–1行,每行包括两个整数 A 和 B,表示 A 和 B 之间有一条主要边;

之后 M 行以同样的格式给出附加边。

对于 20% 的数据,1≤N,M≤100;

对于 100% 的数据,1≤N≤105,1≤M≤2×105 。数据保证答案不超过 231−1。

 

 

输出

 

 

输出一个整数表示答案。

 

 

样例输入

 

4 1
1 2
2 3
1 4
3 4

样例输出

 3

这道题目的主要目标是找出有多少种方式可以将图 "Dark" 斩为两部分。这个过程包括两步:首先,你需要选择一条主要边进行切断,然后,你需要选择一条附加边进行切断。题目的输入包括图的节点数 N,附加边数 M,以及每条主要边和附加边的两个端点。

这个问题的解决方案是基于深度优先搜索(DFS)和最近公共祖先(LCA)的。首先,通过 DFS 构建出每个节点的深度和父节点信息,然后,对于每条附加边,找出它的两个端点的 LCA,并更新相关节点的计数。最后,通过遍历所有节点,根据每个节点的计数,计算出总的方案数。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+10,inf = 0x3f3f3f3f;
int n,m,head[N],cnt = 0,dep[N],f[N][21]; // 定义全局变量,包括节点数 n,附加边数 m,每个节点的邻接表头 head,边数 cnt,每个节点的深度 dep,以及用于存储每个节点的 2^j 级祖先的数组 f
int s[N]; // 定义数组 s,用于存储每个节点的计数
ll ans = 0; // 定义变量 ans,用于存储总的方案数
struct node{
    int to,pre;
}e[N * 2]; // 定义边的结构体,包括边的另一个端点 to 和前一条边的编号 pre
void add(int x,int y)
{
    e[++cnt].pre = head[x];
    e[cnt].to = y;
    head[x] = cnt; // 定义函数 add,用于添加一条从 x 到 y 的边
}
void dfs(int x,int fa)
{
    dep[x] = dep[fa] + 1;
    for(int i = 1; i <= 20; i++)
        f[x][i] = f[f[x][i - 1]][i - 1]; // 计算节点 x 的每个 2^j 级祖先
    for(int i = head[x]; i; i = e[i].pre)
    {
        int v = e[i].to;
        if(v == fa)continue;
        f[v][0] = x;
        dfs(v,x); // 对节点 x 的每个子节点进行深度优先搜索
    }
}
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]; // 将节点 x 提升到和节点 y 同一深度
        if(x == y)return x;
    }
    for(int i = 20; i >= 0; i--)
    {
        if(f[x][i] != f[y][i])
        {
            x = f[x][i];
            y = f[y][i]; // 同时提升节点 x 和节点 y,直到它们的祖先相同
        }
    }
    return f[x][0]; // 返回节点 x 和节点 y 的最近公共祖先
}
void sum(int x,int fa)
{
    for(int i = head[x]; i; i = e[i].pre)
    {
        int  v = e[i].to;
        if(v == fa) continue;
        sum(v,x);
        s[x] += s[v]; // 对节点 x 的每个子节点进行深度优先搜索,并更新节点 x 的计数
    }
}
int main()
{
    scanf("%d %d",&n,&m); // 读入节点数 n 和附加边数 m
    for(int i = 1; i < n; i++)
    {
        int x,y;
        scanf("%d %d",&x,&y); // 读入每条主要边的两个端点
        add(x,y);add(y,x); // 添加两条边,分别是从 x 到 y 和从 y 到 x
    }
    dfs(1,0); // 从节点 1 开始进行深度优先搜索
    for(int i = 1; i <= m; i++)
    {
        int x,y;
        scanf("%d %d",&x,&y); // 读入每条附加边的两个端点
        int t = lca(x,y); // 计算节点 x 和节点 y 的最近公共祖先
        s[t] -= 2;
        s[x]++,s[y]++; // 更新相关节点的计数
    }
    sum(1,0); // 从节点 1 开始进行深度优先搜索,并更新每个节点的计数
    for(int i = 2; i <= n; i++)
    {
        if(s[i] == 0) ans += m; // 如果节点 i 的计数为 0,那么可以选择任意一条附加边进行切断,所以方案数增加 m
        if(s[i] == 1) ans++; // 如果节点 i 的计数为 1,那么只有一种方案,所以方案数增加 1
    }
    printf("%lld",ans); // 输出总的方案数
    return 0;
}

 

 

标签:6577,int,差分,Dark,dep,附加,LCA,切断,节点
From: https://www.cnblogs.com/jyssh/p/17759879.html

相关文章

  • 三个主要降维技术对比介绍:PCA, LCA,SVD
    前言 本文将深入研究三种强大的降维技术——主成分分析(PCA)、线性判别分析(LDA)和奇异值分解(SVD)。我们不仅介绍这些方法的基本算法,而且提供各自的优点和缺点。本文转载自DeepHubIMBA作者:IndraneelDuttaBaruah仅用于学术分享,若侵权请联系删除欢迎关注公众号CV技术指南,专......
  • Conveyor (CF E) (dp 差分/前缀 条件迷惑t)
     思路: 找各种性质1每一秒只有史莱姆进入起始点,然后他会选一个方向走(右或者下),每一秒史莱姆都会这样走在考虑前t秒内有S个史莱姆到达这个点,然后就会有s+1/2个往右走,s/2往下走而且问t秒只会有t-n-m-1秒后的时刻影响(诈骗t)于是利用dp+差......
  • 三个主要降维技术对比介绍:PCA, LCA,SVD
    随着数据集的规模和复杂性的增长,特征或维度的数量往往变得难以处理,导致计算需求增加,潜在的过拟合和模型可解释性降低。降维技术提供了一种补救方法,它捕获数据中的基本信息,同时丢弃冗余或信息较少的特征。这个过程不仅简化了计算任务,还有助于可视化数据趋势,减轻维度诅咒的风险,并提......
  • P5960 差分约束
    原题曾经会过对于\(x_i-x_j\leqk\),我们发现长得很像最短路/最长路的形式,因此我们可以抽象建图建一个超级源点连向所有点,从超级原点跑最短路算法,跑出来的\(dis_i\)即对应\(x_i\)的一个解前文提到过,差分约束问题可以转化为最短路或最长路问题,所以两种转化也就形成了两......
  • 浅谈关于LCA
    prologue本身只会tarjan和倍增法求LCA的,但在发现有一种神奇的\(O(1)\)查询lca的方法,时间优化很明显。mainbody倍增法先讨论倍增法,倍增法求lca是一种很常见普遍的方法,这里直接放代码了,其本身的内核就是让较低点每次都跳$2^k$步,如果跳的比另一个高了,就不跳那......
  • 二阶差分——进行一个等差数列的加
    一般的差分用于对一段区间进行加减,但如果在该区间内加减的是一段等差数列呢?对于一段区间[l,r],加一段首项为s,末项为e的等差数列。其公差d=(s-e)/(r-l+1)为简化问题讨论,先假设这段区间都为0。原数组:0000000添加后的数组:0046800第一次差分:00422-8......
  • CAD设计软件下载-CorelCAD 2020官网版 各个版本下载
    CorelCAD2014是Corel公司推出的一款强大CAD制图工具,使用CorelCAD,用户可以轻松创建专业的CAD图形,CorelCAD使用DWG格式作为其主要的图形文件格式,最高支持版本为2014的DWG和DXF文件,提供了与全球范围内大量图形软件和建筑软件的兼容性和交换功能;新版本优化了基于功能区的用户......
  • 基本差分算法:一维差分、二维差分
    1、一维差分首先要知道,差分是前缀和的逆运算,a1a2……an前缀和b1b2……bn差分以AcWing.797为例,题目要求如下:输入一个长度为n的整数序列。接下来输入m个操作,每个操作包含三个整数l,r,c,表示将序列中[l,r]之间的每个数加上c。请你输出进行完所有操作后的序......
  • dfs 序 O(nlogn)-O(1) 求 LCA
    学点分树,发现不会询问复杂度\(O(1)\)的LCA。于是被迫递归式学习。我们设\(dfn_i\)表示点\(i\)在dfs过程中第几个被访问到,把点按访问到的顺序排序得到的序列叫dfs序。考虑\(u\)和\(v\)在dfs序上的位置之间的这一段序列有什么。设\(lca(u,v)=x,dfn_u<dfn_v\)。......
  • 牛客-小Why的商品归位(差分、区间和)
    链接:https://ac.nowcoder.com/acm/contest/64384/C来源:牛客网超市里一共有\(n\)个货架,\(m\)个商品,一开始商品的位置是被打乱的,小Why需要将商品全部归位。小Why在给货架编号后,实现了每个商品所在货架必然在其应在货架之前。小Why决定手推购物车按编号顺序依次访问每个货架。......