CodeChef October Lunchtime 2019 Division 2
HIT: Khaled in HIT
题目描述
Khaled 教练是 HIT(Hag Institute of Technology)一位名师。但是,他有一些困扰。
最近,Khaled 教练正在教一门课,讲使用电视天线构建 8G 网络并使用汇编语言对它们进行编程。他的班级有 \(N\) 名学生(编号从 \(1\) 到 \(N\));由于某种原因,该数字总是 \(4\) 的倍数。期末考试已结束,Khaled 拿到了他所有 \(N\) 名学生的分数。对于每个 \(i\),第 \(i\) 个学生的分数为 \(A_i\);每个分数是 \(0\) 到 \(100\) 之间的整数。当前,分数等级分布如下:
- 分数小于 \(60\) 为 D 级
- 分数大于或等于 \(60\),但小于 \(75\) 则为 C 级
- 分数大于或等于 \(75\) 但小于 \(90\) 的 B 级
- 分数等于或大于 \(90\) 的 A 级
但是,Khaled 教练对此并不满意。他希望得到每个等级(A,B,C 和 D)的恰好有 \(\frac{N}{4}\) 名学生,以便各等级成绩达到完美平衡。学生的分数无法更改,但等级之间的界限可以更改。因此,他想选择三个整数 \(x, y, z\),并将等级分布规定为以下形式(可以发现原来的方案中,\(x = 60, y = 75, z = 90\)):
- 分数小于 \(x\) 为 D 级
- 分数大于或等于 \(x\),但小于 \(y\) 则为 C 级
- 分数大于或等于 \(y\),但小于 \(z\) 的 B 级
- 分数等于或大于 \(z\) 的 A 级
请你找到找到能使等级达到完美平衡的界限 \(x\), \(y\), \(z\)。如果有多种方案,请选择 \(x + y + z\) 最大的方案(因为教练 Khaled 希望显得比他的学生更聪明);可以证明,最多只有一种这样的方案。有时,不存在满足条件选择界限的方法,此时 Khaled 教练会引咎辞职,因为他的试题质量低下。
输入格式
输入数据第一行包含一个整数 \(T\),表示数据组数。接下来是 \(T\) 组数据。
每组数据第一行包含一个整数 \(N\)。
第二行包含 \(N\) 个整数 \(A_1, A_2, \cdots, A_N\)。输出格式
对于每组数据,如果无解,输出一行包含一个整数 \(-1\);否则输出一行包含三个整数 \(x, y, z\)。
数据范围
- \(1 \le T \le 1000\)
- \(4 \le N \le 100\)
- \(N\) 能被 \(4\) 整除
- \(0 \le A_i \le 100\)
- 各组数据中 \(N\) 的和不超过 \(5000\)
子数据集
- 数据集 1(100 分):无特殊限制
样例数据
输入
6
4
90 25 60 75
8
27 29 92 92 67 67 85 92
4
0 1 2 3
4
100 100 100 100
4
30 30 40 50
4
30 40 40 50
输出
60 75 90
-1
1 2 3
-1
-1
-1
样例解释
第一组数据中,默认方案就是最好的方案。
第四组数据中,所有学生分数都一样,因此不可能有满足条件的方案。时限
\(1\) 秒
在四分点处截断即可。
时间复杂度 \(\mathcal{O}(n \log n)\)。
#include <algorithm>
#include <cstdio>
#include <cstring>
const int MaxN = 100 + 5;
int T, N;
int A[MaxN];
void init() {
scanf("%d", &N);
for (int i = 1; i <= N; ++i) scanf("%d", &A[i]);
}
void solve() {
std::sort(A + 1, A + 1 + N);
for (int i = 1; i + (N / 4) <= N; i += (N / 4)) {
if (A[i + (N / 4) - 1] == A[i + (N / 4)]) {
puts("-1");
return;
}
}
for (int i = 1; i + (N / 4) <= N; i += (N / 4))
printf("%d%c", A[i + (N / 4)], " \n"[i + (N / 2) > N]);
}
int main() {
scanf("%d", &T);
for (int t = 1; t <= T; ++t) {
init();
solve();
}
return 0;
}
INVYCNT: Counting Inversions Revisited
题目描述
Almir 有一个短序列 \(A_1, A_2, \dots, A_N\)。他决定把这个序列复制 \(K\) 次并依次首尾相接起来,得到序列 \(X_1, X_2, \dots, X_{NK}\),其中对于每个 \(1 \le i \le N\) 和 \(0 \le j < K\),有 \(X_{j \cdot N + i} = A_i\)。
例如,当 \(A = (1, 2, 3)\),\(K = 4\),得到的序列为 \(X = (1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3)\)。
对于满足 \(1 \le i < j \le N\) 的数对 \((i, j)\),当 \(X_i > X_j\) 时我们称 \((i, j)\) 是 \(X\) 的一个逆序对。
请你算出最后得到的序列 \(X\) 中的逆序对的数量。
输入格式
输入数据第一行包含一个整数 \(T\),表示数据组数。接下来是 \(T\) 组数据。
每组数据第一行包含两个整数 \(N, K\)。
第二行包含 \(N\) 个整数 \(A_1, A_2, \dots, A_N\)。输出格式
对于每组数据,输出一行包含一个整数表示 \(X\) 中的逆序对的数量。
数据范围
- \(1 \le T \le 1000\)
- \(1 \le N \le 100\)
- \(1 \le K \le 10^6\)
- \(1 \le A_i \le 10^9\)
子数据集
- 数据集 1(100 分):无特殊限制
样例数据
输入
2
3 3
2 1 3
4 100
99 2 1000 24
输出
12
30000
时限
\(1\) 秒
把答案分为两类统计:段内的和跨段的。
段内的就是 \(A\) 的逆序对个数乘上出现次数 \(K\)。
跨段的就是对每个数,找出 \(A\) 中比它小的数个数,然后乘上出现次数,即一个等差数列 \((K - 1) + (K - 2) + \cdots + 1\)。
时间复杂度 \(\mathcal{O}(n \log n)\)。
#include <algorithm>
#include <cstdio>
#include <cstring>
const int MaxN = 100 + 5;
int Te, N, K;
int A[MaxN], D[MaxN];
int Buc[MaxN];
struct BIT {
int t[MaxN];
inline int lowbit(int i) { return i & -i; }
inline void clear() {
memset(t, 0, sizeof t);
}
inline void update(int x, int v) {
if (x == 0) {
t[0] += v;
return;
}
for (int i = x; i <= N; i += lowbit(i))
t[i] += v;
}
inline int query(int x) {
int res = t[0];
for (int i = x; i > 0; i -= lowbit(i))
res += t[i];
return res;
}
};
BIT T;
void init() {
T.clear();
memset(Buc, 0, sizeof Buc);
scanf("%d %d", &N, &K);
for (int i = 1; i <= N; ++i) {
scanf("%d", &A[i]);
D[i] = A[i];
}
std::sort(D + 1, D + 1 + N);
for (int i = 1; i <= N; ++i)
A[i] = std::lower_bound(D + 1, D + 1 + N, A[i]) - D;
}
void solve() {
long long ans1 = 0;
for (int i = N; i >= 1; --i) {
ans1 += T.query(A[i] - 1);
T.update(A[i], 1);
}
ans1 *= K;
long long ans2 = 0;
for (int i = 1; i <= N; ++i) Buc[A[i]]++;
for (int i = 1; i <= N; ++i) Buc[i] += Buc[i - 1];
for (int i = 1; i <= N; ++i)
ans2 += 1LL * Buc[A[i] - 1] * K * (K - 1) / 2;
printf("%lld\n", ans1 + ans2);
}
int main() {
scanf("%d", &Te);
for (int t = 1; t <= Te; ++t) {
init();
solve();
}
return 0;
}
BOXGAM97: Box Game
题目描述
桌子上有 \(N\) 个盒子,从左到右从 \(1\) 到 \(N\) 编号。每个盒子上都写有一个数字;我们用 \(A_i\) 来表示写在 \(i\) 号盒子上的数字。
Jafar 和 Almir 这两个玩家在玩一个持续 \(K\) 回合的游戏。在游戏开始之前,他们掷硬币决定谁先行动。你将根据掷硬币的结果被告知起始玩家。
- 在第一个回合中,先手玩家将一个球放置在他选择的任意盒子中。
- 之后,两名玩家进行游戏。(因此,在第二个回合中,另一名玩家将行动)。
- 在每一回合,行动的玩家可以将球向左移动一个盒子(除非已在 \(1\) 号盒子中)或向右移动一个盒子(除非已在 \(N\) 号盒子中)。
Jafar 的目标是,在比赛结束时,装有球的盒子上写的数字尽可能大。相反,Almir 希望该数字尽可能小。
你知道哪个玩家先手。假设两个玩家都按最优策略行动,试确定游戏的结果。
输入格式
输入数据第一行包含一个整数 \(T\),表示数据组数。接下来是 \(T\) 组数据。
每组数据第一行包含三个整数 \(N, K, P\),其中 \(P\) 表示先手玩家(当 \(P = 0\) 为 Jafer,当 \(P = 1\) 为 Almir)。
第二行包含 \(N\) 个整数 \(A_1, A_2, \dots, A_N\)。输出格式
对于每组数据,输出一行包含在双方都按最优策略行动的前提下的游戏结果。
数据范围
- \(1 \le T \le 1000\)
- \(2 \le N \le 100\)
- \(1 \le K \le 10^9\)
- \(0 \le P \le 1\)
- \(1 \le Ai \le 10^9\)
子数据集
- 数据集 1(100 分):无特殊限制
样例数据
输入
2
4 3 0
4 1 9 5
4 3 1
4 1 9 5
输出
9
1
时限
\(1\) 秒
由于 \(P = 1\) 可以通过把所有 \(A_i\) 转为相反数的方式转为 \(P = 0\),因此以下只讨论 \(P = 0\) 的情况。
分 \(K\) 的奇偶性讨论。
当 \(K\) 为奇数时,无论后手怎么操作,先手都能把球移回来原先的位置。因此先手 Jafer 只需要把球放在最大的盒子上即可。
当 \(K\) 为偶数时,可以证明每次先手所做的操作如果没有抵消后手所做的操作(比如说后手往左操作,先手也往左操作),是不会让结果更优的,因为这样相当于换了一个出发点。因此只剩下后手最后一次机会进行移动,而后手一定移动到较小的位置。那么我们设 \(B_i = \min(A_{i - 1}, A_{i + 1})\),\(B_i\) 的最大值就是答案。
时间复杂度 \(\mathcal{O}(n)\)。
#include <algorithm>
#include <cstdio>
#include <cstring>
const int MaxN = 100 + 5;
const int INF = 0x7F7F7F7F;
int Te, N, K, P;
int A[MaxN];
void init() {
scanf("%d %d %d", &N, &K, &P);
for (int i = 1; i <= N; ++i) scanf("%d", &A[i]);
}
inline void print(int x) {
if (P == 0) printf("%d\n", x);
else printf("%d\n", -x);
}
void solve() {
if (P == 1)
for (int i = 1; i <= N; ++i) A[i] *= -1;
if (K % 2 == 0) {
int Mx = -INF;
A[0] = A[N + 1] = INF + 1;
for (int i = 1; i <= N; ++i) {
int res = std::min(A[i - 1], A[i + 1]);
Mx = std::max(Mx, res);
}
print(Mx);
} else {
int Mx = -INF;
for (int i = 1; i <= N; ++i)
Mx = std::max(Mx, A[i]);
print(Mx);
}
}
int main() {
scanf("%d", &Te);
for (int t = 1; t <= Te; ++t) {
init();
solve();
}
return 0;
}
INVZCNT: Counting Inversions Again!
题目描述
给定一个非负整数序列 \(A_1, A_2, \dots, A_N\)。对于满足 \(1 \le x < y \le N\) 的数对 \((x, y)\),当 \(A_x > A_y\) 时我们称 \((x, y)\) 是一个逆序对。
你需要回答 \(Q\) 次询问(标号 \(1\) 到 \(Q\))。在第 \(i\) 次询问中:
- 给定一个非负整数 \(K_i\)
- 考虑序列 \(B_1, B_2, \dots, B_N\),其中 \(B_j = A_j \oplus K_i\)
- 你需要找到 \(B\) 中的逆序对的数量
输入格式
输入数据第一行包含一个整数 \(T\),表示数据组数。接下来是 \(T\) 组数据。
每组数据第一行包含两个整数 \(N, Q\)。
第二行包含 \(N\) 个整数 \(A_1, A_2, \dots, A_N\)。
第三行包含 \(Q\) 个整数 \(K_1, K_2, \dots, K_Q\)。输出格式
对于每组数据,输出 \(Q\) 行,每行包含一个整数表示该询问的答案(逆序对数)。
数据范围
- \(1 \le T \le 10\)
- \(1 \le N, Q \le 10^6\)
- \(0 \le K_i < 2^{31}\)
- \(0 \le A_i < 2^{31}\)
- 各组数据中 \(N\) 的总和不超过 \(10^6\)
- 各组数据中 \(Q\) 的总和不超过 \(10^6\)
子数据集
- 数据集 1(50 分):
- \(1 \le Q ≤ 5\)
- \(1 \le N \le 10^5\)
- 各组数据中 \(N\) 的总和不超过 \(10^5\)
- 各组数据中 \(Q\) 的总和不超过 \(5\)
- 数据集 2(50 分):无特殊限制
样例数据
输入
1
4 4
3 1 2 0
0
1
2
3
输出
5
3
3
1
时限
\(3\) 秒
首先求出初始逆序对数 \(res\),考虑每次异或对答案的影响。
发现对于两个位置 \(i < j\),倘若 \(A_i > A_j\),那么一定存在一位 \(d\) \((0 \le d \le 30)\),满足 \(A_i, A_j\) 在二进制表示中,第 \(30\) 位到第 \(d + 1\) 位都相同,第 \(d\) 位上 \(A_i\) 为 \(0\),\(A_j\) 为 \(1\)。那么一旦异或的 \(K\) 的第 \(d\) 位为 \(1\),就一定会改变这一对的大小关系,即减小一个逆序对。反之 \(A_i < A_j\) 亦然,可能增加一个逆序对。
而这是改变逆序对的必然条件:任意两个数只会对它们那个不同的最高位产生影响。
因此我需要对于每一位求出,若 \(K\) 的这一位有 \(1\),对答案的贡献量是多少。这只需要从左到右扫一遍,存 \(31\) 个哈希表表示考虑了第 \([30, \cdots, i]\) 位,值为 \(x\) (也就是小于 \(i\) 的位全部当 \(0\) 处理)的方案数,那么每次枚举到一个新数,用 \(x \oplus 2^i\) 的方案数相应地改变这位上的贡献了,然后把 \(x\) 加进哈希表里。
查询时直接每一位的改变量相加即可。
时间复杂度 \(\mathcal{O}(n \log A_i)\)。
#include <algorithm>
#include <cstdio>
#include <cstring>
const int MaxN = 1000000 + 5;
const int Mod = 233333;
int Te, N, Q;
int A[MaxN];
long long F[31];
struct Hash {
int cnt;
int Head[Mod], Next[MaxN], V1[MaxN], F[MaxN];
inline void clear() {
memset(Head, 0, sizeof Head);
for (int i = 1; i <= cnt; ++i) Next[i] = V1[i] = F[i] = 0;
cnt = 0;
}
inline void add(int x) {
int h = x % Mod;
for (int i = Head[h]; i; i = Next[i]) {
if (V1[i] == x) {
F[i]++;
return;
}
}
cnt++;
V1[cnt] = x; F[cnt] = 1;
Next[cnt] = Head[h]; Head[h] = cnt;
}
inline int query(int x) {
int h = x % Mod;
for (int i = Head[h]; i; i = Next[i])
if (V1[i] == x) return F[i];
return 0;
}
};
Hash H;
void init() {
for (int i = 0; i <= 30; ++i) F[i] = 0;
scanf("%d %d", &N, &Q);
for (int i = 1; i <= N; ++i) scanf("%d", &A[i]);
}
namespace CalcInv {
struct BIT {
int t[MaxN];
inline void clear() { for (int i = 0; i <= N; ++i) t[i] = 0; }
inline int lowbit(int i) { return i & -i; }
inline void update(int x, int v) {
if (x == 0) { t[0] += v; return; }
for (int i = x; i <= N; i += lowbit(i)) t[i] += v;
}
inline int query(int x) {
int res = t[0];
for (int i = x; i > 0; i -= lowbit(i)) res += t[i];
return res;
}
};
int a[MaxN], d[MaxN];
BIT T;
long long solve() {
T.clear();
for (int i = 1; i <= N; ++i) d[i] = A[i];
std::sort(d + 1, d + 1 + N);
for (int i = 1; i <= N; ++i) a[i] = std::lower_bound(d + 1, d + 1 + N, A[i]) - d;
long long res = 0;
for (int i = N; i >= 1; --i) {
res += T.query(a[i] - 1);
T.update(a[i], 1);
}
return res;
}
}
void solve() {
long long res = CalcInv::solve();
for (int j = 0; j <= 30; ++j) {
H.clear();
for (int i = 1; i <= N; ++i) {
int x = (A[i] >> j);
if (x & 1) {
F[j] += H.query(x ^ 1);
H.add(x);
} else {
F[j] -= H.query(x | 1);
H.add(x);
}
}
}
for (int i = 1; i <= Q; ++i) {
int x;
long long ans = res;
scanf("%d", &x);
for (int j = 0; j <= 30; ++j)
if (x & (1 << j)) ans += F[j];
printf("%lld\n", ans);
}
}
int main() {
scanf("%d", &Te);
for (int t = 1; t <= Te; ++t) {
init();
solve();
}
return 0;
}
DDQUERY: Double Distance Query
题目描述
给定一棵含 \(N\) 个点(标号 \(1\) 到 \(N\))的无权树。我们记点 \(p\) 和点 \(q\) 之间的距离为 \(d(p, q)\)。
你需要回答 \(Q\) 次询问。每次询问中,给定参数 \(a, d_a, b, d_b\),需要找到一个点 \(x\) 满足 \(d(x, a) = d_a\) 且 \(d(x, b) = d_b\),或者判断这样的点不存在。
输入格式
输入数据第一行包含一个整数 \(T\),表示数据组数。接下来是 \(T\) 组数据。
每组数据第一行包含两个整数 \(N, Q\)。
接下来的 \(N - 1\) 行每行包含两个整数 \(u, v\),表示点 \(u\) 和点 \(v\) 之间有一条边相连。
接下来的 \(Q\) 行每行包含四个整数 \(a, d_a, b, d_b\),描述一个询问。输出格式
对于每次询问输出一行包含一个整数表示一个满足该询问的点的标号,或者输出 \(-1\) 表示无解。
当询问有多解时,输出任意一个即可。数据范围
- \(1 \le T \le 1000\)
- \(1 \le N, Q \le 10^6\)
- \(1 \le u, v \le N\)
- 给定的图是一棵树
- \(1 \le a, b \le N\)
- \(1 \le d_a, d_b < N\)
- 各组数据中 \(N\) 的和不超过 \(10^6\)
- 各组数据中 \(Q\) 的和不超过 \(10^6\)
子数据集
- 数据集 1(50 分):
- \(1 \le N, Q \le 1000\)
- 各组数据中 \(N\) 的和不超过 \(1000\)
- 各组数据中 \(Q\) 的和不超过 \(1000\)
- 数据集 2(50 分):无特殊限制
样例数据
输入
1
5 3
1 2
2 3
3 4
3 5
2 1 4 1
2 2 4 2
1 1 2 1
输出
3
5
-1
时限
\(6\) 秒
求解某个距离 \(u\) 为 \(d\) 的点太难了,我们不妨求 \(u\) 能到达的最远点 \(k\),然后用 \(u \to k\) 上的第 \(d\) 个点作为答案。
路径分为三类:\(x\) 经 \(a\) 到达 \(b\)、\(x\) 经 \(b\) 到达 \(a\)、\(x\) 在 \(a \leftrightarrow b\) 这条路径上插入,然后分头走到 \(a\) 和 \(b\)。
注意一下找最远点的过程中,不能与 \(a \leftrightarrow b\) 这条路径重合。因此需要对每个点维护三个值:最深子树中最深的节点、次深子树中最深的节点、第三深子树中最深的节点,然后判断是否重合来决定取哪个作为最远点。
向上的最远点可以边深搜边 DP 出来。
分类讨论处理一下就可以了,时间复杂度 \(\mathcal{O}(n \log n)\)。
#include <algorithm>
#include <cstdio>
#include <cstring>
const int MaxN = 1000000 + 5;
const int MaxLog = 20;
struct Graph {
int cnte;
int Head[MaxN], To[MaxN * 2], Next[MaxN * 2];
inline void addEdge(int from, int to) {
cnte++; To[cnte] = to;
Next[cnte] = Head[from]; Head[from] = cnte;
}
};
int Te, N, Q;
int Fa[MaxLog + 1][MaxN], Dep[MaxN];
int Id[MaxN], Siz[MaxN], Dfc;
int D[MaxN];
Graph G;
void init() {
scanf("%d %d", &N, &Q);
for (int i = 1; i < N; ++i) {
int u, v;
scanf("%d %d", &u, &v);
G.addEdge(u, v);
G.addEdge(v, u);
}
}
struct Triple {
int st, nd, rd;
Triple(int _st = 0, int _nd = 0, int _rd = 0) {
st = _st;
nd = _nd;
rd = _rd;
}
inline void add(int x) {
if (Dep[x] > Dep[st]) {
rd = nd;
nd = st;
st = x;
} else if (Dep[x] > Dep[nd]) {
rd = nd;
nd = x;
} else if (Dep[x] > Dep[rd]) {
rd = x;
}
}
};
Triple A[MaxN];
void dfs1(int u) {
Dfc++;
Id[u] = Dfc;
Siz[u] = 1;
A[u] = Triple(u, u, u);
for (int i = G.Head[u]; i; i = G.Next[i]) {
int v = G.To[i];
if (v == Fa[0][u]) continue;
Fa[0][v] = u;
Dep[v] = Dep[u] + 1;
for (int j = 1; (1 << j) <= Dep[v]; ++j)
Fa[j][v] = Fa[j - 1][Fa[j - 1][v]];
dfs1(v);
Siz[u] += Siz[v];
A[u].add(A[v].st);
}
}
inline int getKthParent(int u, int k) {
for (int i = MaxLog; i >= 0; --i)
if (k & (1 << i)) u = Fa[i][u];
return u;
}
inline int getLca(int u, int v) {
if (Dep[u] < Dep[v]) std::swap(u, v);
u = getKthParent(u, Dep[u] - Dep[v]);
if (u == v) return u;
for (int i = MaxLog; i >= 0; --i)
if (Fa[i][u] != Fa[i][v]) {
u = Fa[i][u];
v = Fa[i][v];
}
return Fa[0][u];
}
inline int pathLen(int u, int v) {
int l = getLca(u, v);
return Dep[u] + Dep[v] - 2 * Dep[l];
}
inline int pathKth(int u, int v, int k) {
int l = getLca(u, v);
int d = Dep[u] + Dep[v] - 2 * Dep[l];
if (k > d) return -1;
if (k <= Dep[u] - Dep[l]) return getKthParent(u, k);
else return getKthParent(v, d - k);
}
inline bool inSubtree(int u, int v) {
if (Id[u] <= Id[v] && Id[v] < Id[u] + Siz[u]) return true;
else return false;
}
inline bool isParent(int u, int v) {
int d = Dep[u] - Dep[v];
if (d > 0 && getKthParent(u, d) == v) return true;
else return false;
}
inline int getSon(int u, int f) {
int d = Dep[u] - Dep[f];
return getKthParent(u, d - 1);
}
void dfs2(int u, int res) {
D[u] = res;
for (int i = G.Head[u]; i; i = G.Next[i]) {
int v = G.To[i];
if (v == Fa[0][u]) continue;
int newRes = inSubtree(v, A[u].st) ? A[u].nd : A[u].st;
if (pathLen(v, newRes) < pathLen(v, res)) newRes = res;
dfs2(v, newRes);
}
}
void solve() {
dfs1(1);
dfs2(1, 1);
for (int q = 1; q <= Q; ++q) {
int u, du, v, dv;
scanf("%d %d %d %d", &u, &du, &v, &dv);
if (Dep[u] < Dep[v]) {
std::swap(u, v);
std::swap(du, dv);
}
int l = getLca(u, v);
int d = Dep[u] + Dep[v] - 2 * Dep[l];
if (du + d == dv) {
int x = A[u].st;
if (Dep[x] - Dep[u] >= du) {
printf("%d\n", pathKth(u, x, du));
continue;
}
}
if (dv + d == du) {
int x = A[v].st;
if (inSubtree(getSon(u, l), x) == true) x = A[v].nd;
if (Dep[x] - Dep[v] >= dv) {
printf("%d\n", pathKth(v, x, dv));
continue;
}
if (l == v) {
x = D[v];
if (pathLen(x, v) >= dv) {
printf("%d\n", pathKth(v, x, dv));
continue;
}
}
}
if (du + dv >= d && (du + dv - d) % 2 == 0) {
int k = (du + dv - d) / 2;
int m = pathKth(u, v, du - k);
int x = A[m].st;
if ((isParent(u, m) && inSubtree(getSon(u, m), x)) || (isParent(v, m) && inSubtree(getSon(v, m), x))) x = A[m].nd;
if ((isParent(u, m) && inSubtree(getSon(u, m), x)) || (isParent(v, m) && inSubtree(getSon(v, m), x))) x = A[m].rd;
if (Dep[x] - Dep[m] >= k) {
printf("%d\n", pathKth(m, x, k));
continue;
}
if (m == l) {
x = D[m];
if (pathLen(x, m) >= k) {
printf("%d\n", pathKth(m, x, k));
continue;
}
}
}
puts("-1");
}
}
void clear() {
for (int i = 1; i <= N; ++i) {
Dep[i] = 0;
Siz[i] = 0;
Id[i] = 0;
D[i] = 0;
G.Head[i] = 0;
for (int j = 0; j <= MaxLog; ++j) Fa[j][i] = 0;
A[i] = Triple();
}
for (int i = 1; i <= G.cnte; ++i)
G.To[i] = G.Next[i] = 0;
G.cnte = 0;
Dfc = 0;
}
int main() {
scanf("%d", &Te);
for (int t = 1; t <= Te; ++t) {
init();
solve();
clear();
}
return 0;
}
CodeChef October Lunchtime 2019 Division 2的更多相关文章
- Codechef October Challenge 2019 Division 1
Preface 这次CC难度较上两场升高了许多,后面两题都只能借着曲明姐姐和jz姐姐的仙气来做 值得一提的是原来的F大概需要大力分类讨论,结果我写了一大半题目就因为原题被ban了233 最后勉强涨了近 ...
- Codechef April Challenge 2019 Division 2
Maximum Remaining 题意:给n个数,取出两个数$a_{i}$,$a_{j}$,求$a_{i}\% a_{j}$取模的最大值 直接排个序,第二大(严格的第二大)模第一大就是答案了. #i ...
- Codechef November Challenge 2019 Division 1
Preface 这场CC好难的说,后面的都不会做QAQ 还因为不会三进制位运算卷积被曲明姐姐欺负了,我真是太菜了QAQ PS:最后还是狗上了六星的说,期待两(三)场之内可以上七星 Physical E ...
- Codechef September Challenge 2019 Division 2
Preface 这确实应该是我打过的比较水的CC了(其实就打过两场) 但由于我太弱了打的都是Div2,所以会认为上一场更简单,其实上一场Div的数据结构是真的毒 好了废话不多说快速地讲一下 A Eas ...
- Codechef August Challenge 2019 Division 2
Preface 老年菜鸡终于开始打CC了,由于他太弱了所以只能打Div2 因为台风的原因challenge并没有写,所以水了个Rank7 A Football SB模拟题不解释 #include< ...
- CodeChef November Challenge 2019 Division 1题解
传送门 AFO前的最后一场CC了--好好打吧-- \(SIMGAM\) 偶数行的必定两人平分,所以只要抢奇数行中间那个就行了 这题怎么被爆破了 //quming #include<bits/st ...
- Codechef July Challenge 2019 Division 1题解
题面 \(CIRMERGE\) 破环成链搞个裸的区间\(dp\)就行了 //quming #include<bits/stdc++.h> #define R register #defin ...
- Codechef April Challenge 2019 游记
Codechef April Challenge 2019 游记 Subtree Removal 题目大意: 一棵\(n(n\le10^5)\)个结点的有根树,每个结点有一个权值\(w_i(|w_i\ ...
- Codechef October Challenge 2018 游记
Codechef October Challenge 2018 游记 CHSERVE - Chef and Serves 题目大意: 乒乓球比赛中,双方每累计得两分就会交换一次发球权. 不过,大厨和小 ...
随机推荐
- ajax post上传数据时,前端出现的跨域权限问题:ccess to XMLHttpRequest at ‘’rom origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok st
本人前端使用多个框架时,jq ajax传参出现如下报错: 最后发现,可能是xhr的相关默认参数被修改了.顾使用jq 传参时,一直报错,jq ajax额外添加的关键参数: crossDomain: ...
- Luogu4022 CTSC2012熟悉的文章(广义后缀自动机+二分答案+动态规划+单调队列)
对作文库中的串建出广义SAM,然后显然可以二分答案,二分之后考虑暴力dp,设f[i]为前i位最长匹配长度,显然有f[i]=max(f[i-1],f[j]+i-j) (i-j>=l&&am ...
- 虚拟机Vmware使用记录
一直使用的是docker for windows,但是总会出现能打包,能打tag,但是push超时,所以想着弄个虚拟机来实现. 第一步: 安装VMware,安装一个ubantu最新的系统. 第二步: ...
- 字蛛webfont 安装及使用方法
先安装nodejs和git,比如放在D:/nodejs/ 文件夹 cmd 进入该文件夹,安装npm install express 安装 npm install font-spider -g 安装 ...
- css 关于"浮动边距加倍"及其解决方法-------解决方案是在这个div里面加上display:inline;
写div代码的时候,经常发现明明宽度算得很准确,但是莫明其妙的会和计划的布局不太一样- -|||开始以为自己代码写的有问题,拼命找bug也一无所获,最后可能会稍微修改样式来达到想要的效果,但终究也是外 ...
- 关于微信小程序获取多个formId的实现方法
在此之前,很多人使用过form和button的多层嵌套来实现点击一次获取多个formId的目的,如下图所示,点击一次“提交”,可以获取到多个formId 但是在今年3月份,这个投机取巧的方法(算是微信 ...
- JS数组操作,赋值指向同一指针
1.使用slice() 可使用slice()进行复制,因为slice()返回也是数组. var array1 = new Array("1","2"," ...
- K2 BPM_K2受邀出席QAD 2019年亚太区用户大会_全业务流程管理专家
6月12-13日,K2受邀参加了以“云聚创新,智造未来”为主题的QAD 2019年亚太区用户大会.会议上K2同与会嘉宾们共商制造业数字化转型,就如何用流程赋能企业实现智能制造进行了精彩分享. 近期发布 ...
- Computer Vision_33_SIFT:Distinctive Image Features from Scale-Invariant Keypoints——2004
此部分是计算机视觉部分,主要侧重在底层特征提取,视频分析,跟踪,目标检测和识别方面等方面.对于自己不太熟悉的领域比如摄像机标定和立体视觉,仅仅列出上google上引用次数比较多的文献.有一些刚刚出版的 ...
- 关于PPP拨号 和 AT指令实现GPRS模块联网的疑问
以下内容摘抄自互联网: ppp拨号 与 at命令的疑问 GPRS模块在Linux平台上ppp拨号上网总结与心得 以PPP拨号实现GPRS与因特网的数据通信的具体实现流程 问: 我刚接触GPRS,了解A ...