首页 > 其他分享 >洛谷 P6963

洛谷 P6963

时间:2022-10-27 20:15:38浏览次数:57  
标签:head 路径 洛谷 加入 int dsu dep P6963

不难发现,包含关系只可能是短的路径被长的路径包含。

那么我们考虑按照路径长度从小到大,一条一条路径边加入边判断。

考虑先将树上的所有边断开,每加入一条路径的时候就将这条路径上包含的边加入,用并查集维护连通块的点数。不难发现,如果加入一条路径后,这条路径所在连通块的点数与当前加入的这条路径上的点数不同时,就必然存在一条路径,与当前加入的这条路径不满足题目所给命题,此时可以判定不成立了。如果加入后点数相符合,那么当前就没有问题。

如果将所有路径都加入了还没出现问题,那么这个命题就可以确定为正确的了。

Code:

#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, m, t;
int head[N], ver[N*2], nxt[N*2], cnt;
int fa[N][18], dep[N];

void add(int u, int v) {
	ver[++cnt] = v, nxt[cnt] = head[u], head[u] = cnt;
}

void dfs(int u, int Fa) {
	for (int i = head[u]; i; i = nxt[i]) {
		int v = ver[i];
		if (v == Fa) continue;
		fa[v][0] = u, dep[v] = dep[u] + 1;
		for (int j = 1; j <= t; ++j)
			fa[v][j] = fa[fa[v][j - 1]][j - 1];
		dfs(v, u);
	}
}

int LCA(int x, int y) {
	if (dep[x] > dep[y]) swap(x, y);
	for (int i = t; ~i; --i)
		if (dep[x] <= dep[fa[y][i]]) y = fa[y][i];
	if (x == y) return x;
	for (int i = t; ~i; --i)
		if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
	return fa[x][0];
}

struct Path {
	int x, y, lca, len;
	
	void init() {
		scanf("%d%d", &x, &y), lca = LCA(x, y);
		len = dep[x] + dep[y] - 2 * dep[lca];
	}
	bool operator < (const Path &rhs) const {
		return len < rhs.len;
	}
} a[N];

struct DSU {
	int fa[N], siz[N];
	
	void init() { for (int i = 1; i <= n; ++i) fa[i] = i, siz[i] = 1; }
	int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
	void merge(int x, int y) { x = find(x), y = find(y); if (x == y) return; fa[x] = y, siz[y] += siz[x]; }
} dsu;

void solve(Path cur) {
	int x = dsu.find(cur.x), y = dsu.find(cur.y), lca = cur.lca, len = cur.len;
	while (dep[x] > dep[lca]) dsu.merge(x, fa[x][0]), x = dsu.find(x);
	while (dep[y] > dep[lca]) dsu.merge(y, fa[y][0]), y = dsu.find(y);
	if (len != dsu.siz[dsu.find(lca)] - 1) printf("No"), exit(0);
}

int main() {
	scanf("%d%d", &n, &m), t = (log(n) / log(2)) + 1;
	for (int i = 1, u, v; i < n; ++i) scanf("%d%d", &u, &v), add(u, v), add(v, u);
	dep[1] = 1, dfs(1, 0);
	for (int i = 1; i <= m; ++i) a[i].init();
	sort(a + 1, a + m + 1), dsu.init();
	for (int i = 1; i <= m; ++i) solve(a[i]);
	printf("Yes");
	return 0;
}

标签:head,路径,洛谷,加入,int,dsu,dep,P6963
From: https://www.cnblogs.com/Kobe303/p/16833544.html

相关文章

  • 洛谷 P7023
    首先可以发现一些有用的性质:每个数至多操作一次如果一个数,在原数列中有它的倍数,那么改变成那个数一定是最优的。否则可以改变成所有数的最小公倍数。贪心的,按出现次数......
  • 洛谷P3225 [HNOI2012]矿场搭建
    SLOJH7136.「HNOI2012」矿场搭建题目描述煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援......
  • 洛谷 P8595 「KDOI-02」一个网的路 蓝 题解
    定义树形\(DP\),这个挺明显的,我认为\(DP\)让读者理解的最重要的一步是:定义。所以我先详细说明\(f\)数组的定义,至于为什么这么定义后面再讲。\(f_{u,type}\),其中\(......
  • 洛谷 P3592
    首先不难发现最终答案中只会出现\(c_i\)中的数,所以可以将\(c_i\)离散化。设\(f_{i,j,k}\)表示区间\([l,r]\),最小值不小于\(k\)的最大收益,\(cnt_{i,j}\)表示区间......
  • 洛谷P1021题解
    原题P1021[NOIP1999提高组]邮票面值设计思路概述题意分析给定两个整数\(N,K(N+K≤15)\),设计\(K\)种邮票面值\(\{a_1,a_2\dotsa_K\}\),并用共\(N\)张上述邮票......
  • 洛谷P1064题解
    原题P1064[NOIP2006提高组]金明的预算方案思路概述题意分析给定一个体积为\(n\)的背包和\(m\)个物品。每个物品通过\((\text{价值},\text{体积})\)的形式表......
  • 洛谷 P7003
    考虑当左端点固定时,区间的\(\&\)和至多有\(\logw\)种,因为\(1\)的数量是单调不升的。所以我们可以枚举区间左端点\(i\),然后ST表预处理区间\(\&\)和+二分求出......
  • 洛谷P2512 [HAOI2008]糖果传递
    SLOJP1117.糖果传递题目描述有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为11。输入格式小朋友个数n,下面n行ai​......
  • 洛谷 P6453
    设第\(i\)列高\(h_i\),建立序列\(h_i\)的小根笛卡尔树,然后树形DP。发现这样就将原来不规整的图形剖分成若干个矩形:我们发现,这样构成的若干个矩形正好对应小根笛卡......
  • 洛谷优秀油猴插件推荐
    前言转载自眭然的博客,有改编和新增下载链接油猴zip1.先打开edge浏览器的扩展(其他浏览器应该也可以加扩展,不过edge最好)2.打开开发者模式和允许来自其他应用商店的......