XCPC集训47补题
H - The Tag Game
题目:
Alice got tired of playing the tag game by the usual rules so she offered Bob a little modification to it. Now the game should be played on an undirected rooted tree of n vertices. Vertex 1 is the root of the tree.
Alice starts at vertex 1 and Bob starts at vertex x (x ≠ 1). The moves are made in turns, Bob goes first. In one move one can either stay at the current vertex or travel to the neighbouring one.
The game ends when Alice goes to the same vertex where Bob is standing. Alice wants to minimize the total number of moves and Bob wants to maximize it.
You should write a program which will determine how many moves will the game last.
Input
The first line contains two integer numbers n and x (2 ≤ n ≤ 2·10^5, 2 ≤ x ≤ n).
Each of the next n - 1 lines contains two integer numbers a and b (1 ≤ a, b ≤ n) — edges of the tree. It is guaranteed that the edges form a valid tree.
Output
Print the total number of moves Alice and Bob will make.
Sample 1
Input
4 3
1 2
2 3
2 4
Output
4
Sample 2
Input
5 2
1 2
2 3
3 4
2 5
Output
6
分析:
B必定在A的子树上,为了让步数最少,A定是要朝着B的方向走的,为了让步数最大,B定是要往最深的方向走。
因此,可以分别求出A、B到每个点的距离d1、d2, 如果d1>d2 则说明可行(可自行模拟)。
代码:
/*
qwq!
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <cmath>
#include <unordered_map>
using namespace std;
#define pb push_back
#define pu push
#define fi first
#define se second
#define LL long long
typedef pair<int,int> PII;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 10, M = N << 1;
int h[N], e[M], ne[M], d1[N], d2[N], idx;
int read () {
int k=0,f=1;
char c=getchar ();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar ();}
while (c>='0'&&c<='9') {k=k*10+c-'0';c=getchar ();}
return k*f;
}
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs1(int u, int f, int s) { // 求B到各点的距离
d1[u] = s;
for(int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if(j == f) continue;
dfs1(j, u, s + 1);
}
}
void dfs2(int u, int f, int s) { // 求A到各点的距离
d2[u] = s;
for(int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if(j == f) continue;
dfs2(j, u, s + 1);
}
}
int main() {
int n = read(), x = read();
memset(h, -1, sizeof h);
for(int i = 1; i < n; i++) {
int a = read(), b = read();
add(a, b), add(b, a);
}
dfs1(x, -1, 0);
dfs2(1, -1, 0);
int ans = 0;
for(int i = 1; i <= n; i++) {
if(d1[i] < d2[i]) ans = max(ans, d2[i] * 2);
}
cout << ans << endl;
return 0;
}
J - Harmonious Graph
题目:
You're given an undirected graph with nn nodes and mm edges. Nodes are numbered from 11 to nn.
The graph is considered harmonious if and only if the following property holds:
For every triple of integers (l, m, r) such that $ 1\leq {l} < m < r \leq n $ , if there exists a path going from node l to node r, then there exists a path going from node l to node m.
In other words, in a harmonious graph, if from a node ll we can reach a node rr through edges (l < rl<r), then we should able to reach nodes $ (l+1), (l+2), \ldots, (r-1) too. $
What is the minimum number of edges we need to add to make the graph harmonious?
Input
The first line contains two integers n and m $ (3 \leq n \leq 200000 \ and \ 1\le m \le 200000). $
The i-th of the next m lines contains two integers \(u_i\) and \(v_i\) \((1 \leq u_i, v_i \leq n, u_i \neq v_i)\), that mean that there's an edge between nodes u and v.
It is guaranteed that the given graph is simple (there is no self-loop, and there is at most one edge between every pair of nodes).
Output
Print the minimum number of edges we have to add to the graph to make it harmonious.
Sample 1
Input
14 8
1 2
2 7
3 4
6 3
5 7
3 8
6 8
11 12
Output
1
Sample 2
Input
200000 3
7 9
9 8
4 5
Output
0
分析:
若1->3->7,则应当有1->2,1->4,1->5,1->6,即1-7中所有的点都应该在一个连通块中。因此可以让每个连通块中的父亲节点为连通块的最大值,然后枚举每一个小于当前父节点的点判断其父节点是否小于该父节点,如果不等,则应该连通。也就是加一条边。
代码:
/*
qwq!
*/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <map>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <cmath>
#include <unordered_map>
using namespace std;
#define pb push_back
#define pu push
#define fi first
#define se second
#define LL long long
typedef pair<int,int> PII;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 10;
int f[N];
int read () {
int k=0,f=1;
char c=getchar ();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar ();}
while (c>='0'&&c<='9') {k=k*10+c-'0';c=getchar ();}
return k*f;
}
int find(int x) {
if(x != f[x]) f[x] = find(f[x]);
return f[x];
}
void merge(int a, int b) {
a = find(a), b = find(b);
if(a != b) {
if(a < b) swap(a, b);
f[b] = a;
}
}
int main() {
int n = read(), m = read();
for(int i = 1; i <= n; i++) f[i] = i;
while(m--) {
int a = read(), b = read();
merge(a, b);
}
int ans = 0;
int fa = 0;
int t = 1;
while(t <= n) {
fa = find(t);
for(int i = t + 1; i <= fa; i++) {
int x = find(i);
if(x != fa) {
ans++;
merge(x, fa);
fa = max(fa, x);
}
}
t = fa + 1;
}
cout << ans << endl;
return 0;
}