首页 > 其他分享 >洛谷P10931 闇の連鎖

洛谷P10931 闇の連鎖

时间:2024-08-28 10:04:32浏览次数:8  
标签:树边 洛谷 删除 int 附加 fa P10931 LCA

洛谷P10931 闇の連鎖

题意

给定一棵 \(n\) 个点的树,有 \(m\) 条附加边。

第一次删除一条树边,第二次删除一条附加边。

求有多少种方案使原来的树不联通。

思路

考虑求出 \(f_i\) 表示 \(i\) 的子树中有多少条附加边连向 \(i\) 的子树外。

若 \(f_i=0\),则把 \(i\) 与 \(i\) 的父亲之间的树边删除后树已经不联通,随意删除一条附加边即可,对答案的贡献是 \(m\)。

若 \(f_i=1\),则把 \(i\) 与 \(i\) 的父亲之间的树边删除后,必须删除这条附加边才能满足题意,对答案的贡献是 \(1\)。

若 \(f_i \ge 2\),则把 \(i\) 与 \(i\) 的父亲之间的树边删除后,无论删除哪条附加边都不能满足题意,对答案的贡献是 \(0\)。

现在想想如何求出 \(f_i\)。

对于每条附加边 \((u,v)\),\(u\) 和 \(v\) 对哪些点的 \(f\) 有贡献呢?

从 \(u\) 到 \(LCA(u,v)\)(不含)的路径上,从 \(v\) 到 \(LCA(u,v)\)(不含)的路径上的所有点的 \(f\) 都会加一。

为什么 \(LCA(u,v)\) 以上的点不会有贡献呢?

对于 \(LCA(u,v)\) 及其以上的点 \(x\),\(u\) 和 \(v\) 都在 \(x\) 的子树中,不满足 \(f\) 的定义,即连向子树外的附加边,所以没有贡献。

那怎么快速计算贡献呢?

暴力更改 \(f\) 时间复杂度为 \(O(nm)\),不能通过。

树上路径问题可以想到使用树链剖分,不过太复杂。

可以使用树上差分快速统计。

\(u\) 到 \(LCA(u,v)\) 路径上点权全部加一,等价于 \(u\) 到根节点路径上点权全部加一,\(LCA(u,v)\) 到根节点路径上点权全部减一。

可以把 \(f_u\) 加一,\(f_{LCA(u,v)}\) 减一,最后统计答案时遍历一遍把子树内的信息收上来。\(v\) 同理。

时间复杂度 \(O((n+m)\log n)\)。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 5;
int tot, ver[N << 1], nxt[N << 1], head[N];
int fa[N][22], de[N];
int n, m, a[N], ans;
void add(int x, int y) {
	ver[++ tot] = y;
	nxt[tot] = head[x];
	head[x] = tot;
}
void DFS(int x) {
    de[x] = de[fa[x][0]] + 1;
    for (int i = 1; i <= 19; i ++)
        fa[x][i] = fa[fa[x][i - 1]][i - 1];
    for (int i = head[x], y; i; i = nxt[i]) {
        y = ver[i];
        if (y == fa[x][0]) continue;
        fa[y][0] = x;
        DFS(y);
    }
}
inline int LCA(int x, int y) {
    if (de[x] < de[y]) swap(x, y);
    for (int i = 19; i >= 0; i --) 
        if (de[fa[x][i]] >= de[y]) x = fa[x][i];
    if (x == y) return x;
    for (int i = 19; i >= 0; i --)
        if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
    return fa[x][0];
}
void dfs(int x, int fa) {
	for (int i = head[x], y; i; i = nxt[i]) {
		y = ver[i];
		if (y == fa) continue;
		dfs(y, x);
		a[x] += a[y]; // 把子树信息收上来
	}
}
signed main() {
	cin >> n >> m;
	for (int i = 1, x, y; i < n; i ++) {
		cin >> x >> y;
		add(x, y); add(y, x);
	}
	DFS(1);
	for (int i = 1, x, y; i <= m; i ++) {
		cin >> x >> y;
		a[x] ++, a[y] ++, a[LCA(x, y)] -= 2; // 差分
	}
	dfs(1, 0); // 收集信息
	for (int i = 2; i <= n; i ++) { // 统计答案
		if (!a[i]) {
			ans += m;
		} else if (a[i] == 1) {
			ans ++;
		}
	}
	cout << ans << "\n";
	return 0;
} 

标签:树边,洛谷,删除,int,附加,fa,P10931,LCA
From: https://www.cnblogs.com/maniubi/p/18384033

相关文章

  • 洛谷 P1518 [USACO2.4] 两只塔姆沃斯牛 The Tamworth Two
    [USACO2.4]两只塔姆沃斯牛TheTamworthTwo题目描述两只牛逃跑到了森林里。FarmerJohn开始用他的专家技术追捕这两头牛。你的任务是模拟他们的行为(牛和John)。追击在10×......
  • 洛谷SCP 2024 第一轮(初赛 J 组)模拟题解析(第三部分:完善程序(1-2))
    完善程序一(补全)#include<bits/stdc++.h>usingnamespacestd;constintMAXN=100000;intn;intvis[MAXN],a[MAXN];vector<int>ans;intcheck(intk){intx=n,top=0;for(inti=0;i<=k;i++)vis[i]=0;while(x......
  • 洛谷 P8615 [蓝桥杯 2014 国 C] 拼接平方数
    题面题目描述小明发现很有趣,首先,它是个平方数。它可以拆分为和,拆分出来的部分也是平方数。也有这个性质,我们权且称它们为:拼接平方数。可拆分,这有点勉强,我们规定,等都不算平方数。小明想:还有哪些数字是这样的呢?你的任务出现了:找到某个区间的所有拼接平方数。输入......
  • 洛谷P2440 木材加工 题解
    这是我找到的一篇很久之前为了让我更好理解二分写的详细题解题目链接code:#include<bits/stdc++.h>#defineintlonglong#defineMAXN0x3f3f3f3f3f3f3f3f#defineMINN-0x3f3f3f3f3f3f3f3f#defineMiraiios::sync_with_stdio(0),cin.tie(0),cout.tie(0);usingnamespa......
  • 洛谷P1605 迷宫
    原题题目描述给定一个方格的迷宫,迷宫里有处障碍,障碍处不可通过。在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。给定起点坐标和终点坐标,每个方格最多经过一次,问有多少种从起点坐标到终点坐标的方案。输入格式第一行为三个正整数,分......
  • 将洛谷私信接入Windows
    首先下载一个私信Github:https://github.com/GCSG01/LG_Show_Massger/archive/refs/heads/main.zip然后解压,找到src/settings.json,把你的洛谷cookie和UID填进去,点击Start.cmd运行。(其余的不要改)之后不出意外就会有两个窗口:AI功能:下载仓库:https://github.com/OI-liyi......
  • 洛谷P10878 [JRKSJ R9] 在相思树下 III && 单调队列
    传送门:P10878[JRKSJR9]在相思树下III将军啊,早卸甲,他还在廿二,等你回家……一道练习单调队列的好题qwq题目意思:很明白了,不再复述。(注意$\foralli$表示对于任意的i,可理解为所有)思路:贪心是很明显的,因为我们要让最后的值最大,首先要把小的值删掉。最后的答案就是进......
  • 洛谷P1182 数列分段 Section II
    传送门:P1182数列分段SectionII消灭人类暴政,世界属于三体题目意思:题目说的很明白了思路:考虑部分分:20%的数据保证n<10,直接爆搜;40%的数据保证n<1000,n^2+前缀和搞定100%的数据:求每段最大和的最小值:明显的二分(n在10^5的范围也说明了这一点,因为二分查找的......
  • 洛谷P1540 [NOIP2010 提高组] 机器翻译答案
    #include<bits/stdc++.h>usingnamespacestd;/*数据结构:队列queue 桶:标记某个单词是否出现在内存中 t[i]=false:不在t[i]=true:在对于读入的每个单词x: 如果不存在单词x 存储(入队) t[x]=true 内存中元素个数(q.size())>M: t[q.front()]=falses; ......
  • 洛谷 P2590 [ZJOI2008] 树的统计 题解
    题目大意给你一个\(N\),然后再给你两个长度为\(N\)的序列。让你构造一个仅有\(0\)和\(1\)的\(N\timesN\)的正方形,但是要满足两个序列的顺序:第一个序列指的是该正方形每一行所构成的二进制数的大小顺序。第二个序列指的是该正方形每一列所构成的二进制数的大小顺序。......