QOJ.ac
QOJ
ID | 题目 | 提交者 | 结果 | 用时 | 内存 | 语言 | 文件大小 | 提交时间 | 测评时间 |
---|---|---|---|---|---|---|---|---|---|
#753312 | #9570. Binary Tree | kalikari | WA | 4ms | 3900kb | C++17 | 4.1kb | 2024-11-16 12:19:24 | 2024-11-16 12:19:25 |
Judging History
answer
#include<bits/stdc++.h>
using namespace std;
// 读取输入函数,用于快速读取整数
int Read() {
int x = 0;
char ch = getchar();
bool f = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') f = 1, ch = getchar();
else if (ch == EOF) return 0;
else ch = getchar();
}
while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return f ? -x : x;
}
// 全局变量定义
int fa[100005], l[100005], r[100005]; // fa:父节点,l:左子节点,r:右子节点
int root; // 树的根节点
int siz[100005]; // 子树大小
int n; // 当前节点个数
bool flag; // 标记是否找到重心
// 深度优先搜索,计算子树大小并找到重心
void dfs(int x) {
siz[x] = 1; // 初始化子树大小为1
// 递归处理左子树
if (l[x]) {
dfs(l[x]);
siz[x] += siz[l[x]];
}
// 递归处理右子树
if (r[x]) {
dfs(r[x]);
siz[x] += siz[r[x]];
}
// 如果已经找到重心,直接返回
if (flag) return;
// 检查是否满足重心条件
// 重心条件:去掉当前节点后,剩余连通块大小 <= n / 2
if (siz[l[x]] <= n / 2 && siz[r[x]] <= n / 2 && n - siz[x] + 1 <= n / 2 && l[x] && r[x]) {
flag = 1; // 找到重心
// 查询左右子节点,询问哪个更接近特殊节点
printf("? %d %d\n", l[x], r[x]);
fflush(stdout);
int op = Read();
// 根据交互器返回的结果进行处理
if (op == 1) l[x] = 0, r[x] = 0, n = n - siz[x] + 1; // 相等情况,删除左右子节点
if (op == 2) root = r[x], n = siz[r[x]], fa[r[x]] = 0; // 右子节点更近,更新根节点为右子节点
if (op == 0) root = l[x], n = siz[l[x]], fa[l[x]] = 0; // 左子节点更近,更新根节点为左子节点
return;
}
// 检查父节点和左子节点的情况
if (siz[l[x]] <= n / 2 && siz[r[x]] + 1 <= n / 2 && n - siz[x] <= n / 2 && fa[x] && l[x]) {
flag = 1;
printf("? %d %d\n", l[x], fa[x]);
fflush(stdout);
int op = Read();
if (op == 1) l[x] = 0, fa[x] = 0, root = x, n = siz[r[x]] + 1; // 相等情况,删除左子节点和父节点
if (op == 2) {
n = n - siz[x];
if (l[fa[x]] == x) l[fa[x]] = 0;
if (r[fa[x]] == x) r[fa[x]] = 0;
}
if (op == 0) root = l[x], n = siz[l[x]], fa[l[x]] = 0;
return;
}
// 检查父节点和右子节点的情况
if (siz[l[x]] + 1 <= n / 2 && siz[r[x]] <= n / 2 && n - siz[x] <= n / 2 && fa[x] && r[x]) {
flag = 1;
printf("? %d %d\n", r[x], fa[x]);
fflush(stdout);
int op = Read();
if (op == 1) r[x] = 0, fa[x] = 0, root = x, n = siz[l[x]] + 1;
if (op == 2) {
n = n - siz[x];
if (l[fa[x]] == x) l[fa[x]] = 0;
if (r[fa[x]] == x) r[fa[x]] = 0;
}
if (op == 0) root = r[x], n = siz[r[x]], fa[r[x]] = 0;
return;
}
return;
}
signed main() {
int T = Read(); // 读取测试用例数量
while (T--) {
n = Read(); // 读取节点数量
// 初始化
for (int i = 1; i <= n; i++) fa[i] = 0;
for (int i = 1; i <= n; i++) {
l[i] = Read(), r[i] = Read();
if (l[i]) fa[l[i]] = i;
if (r[i]) fa[r[i]] = i;
}
// 找到根节点
for (int i = 1; i <= n; i++) if (!fa[i]) root = i;
// 使用 DFS 找重心
if (n > 2) {
flag = 0;
dfs(root);
}
// 当 n == 1 时,直接输出根节点
if (n == 1) {
printf("! %d\n", root);
fflush(stdout);
} else {
// 当 n == 2 时,询问根节点和其子节点
printf("? %d %d\n", root, l[root] ? l[root] : r[root]);
fflush(stdout);
int op = Read();
printf("! %d\n", op == 0 ? root : (l[root] ? l[root] : r[root]));
fflush(stdout);
}
}
return 0;
}
详细
Test #1:
score: 100
Accepted
time: 0ms
memory: 3900kb
input:
2 5 0 0 1 5 2 4 0 0 0 0 2 0 2 0 2 0 0 2
output:
? 1 3 ? 3 4 ! 3 ? 1 2 ! 2
result:
ok OK (2 test cases)
Test #2:
score: -100
Wrong Answer
time: 4ms
memory: 3776kb
input:
5555 8 2 0 8 6 0 0 3 0 0 0 7 0 0 0 5 4 2 2
output:
? 5 2 ? 1 2 ! 2
result:
wrong answer There are 3 candidates. (test case 1)