QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#764000 | #9570. Binary Tree | Lynia | RE | 1ms | 3556kb | C++23 | 5.9kb | 2024-11-19 23:17:09 | 2024-11-19 23:17:10 |
Judging History
answer
///////////
// // //
// ////////////////////
// // //
//
///////////
//
//
// // // //////// /\ /////////
// // // // // // //
// //////// // // // // //
// // // // // // //
////////// //////// // // // /////////////
//#pragma GCC optimize(3,"Ofast","inline")
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <string>
#include <cstring>
#include <cmath>
#include <list>
#include <stack>
#include <array>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <random>
#include <numeric>
#include <functional>
#include <optional>
//#include <Windows.h>
using namespace std;
#define fa(i,op,n) for (int i = op; i <= n; i++)
#define fb(j,op,n) for (int j = op; j >= n; j--)
#define pb push_back
#define HashMap unordered_map
#define HashSet unordered_set
#define var auto
#define all(i) i.begin(), i.end()
#define all1(i) i.begin() + 1,i.end()
#define endl '\n'
#define px first
#define py second
using VI = vector<int>;
using VL = vector<long long>;
using ll = long long;
using ull = unsigned long long;
using db = double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
template<class T1, class T2>
ostream& operator<<(ostream& out, const pair<T1, T2>& p) {
out << '(' << p.first << ", " << p.second << ')';
return out;
}
template<typename T>
ostream& operator<<(ostream& out, const vector<T>& ve) {
for (T i : ve)
out << i << ' ';
return out;
}
template<class T1, class T2>
ostream& operator<<(ostream& out, const map<T1, T2>& mp) {
for (auto i : mp)
out << i << '\n';
return out;
}
template<typename ...T>
bool _debug(T... a) {
((cout << a << ' '), ...);
cout << endl;
return -1;
}
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int IINF = 0x7fffffff;
const int iinf = 0x80000000;
const ll LINF = 0x7FFFFFFFFFFFFFFF;
const ll linf = 0x8000000000000000;
int dx[8] = { 1, -1, 0, 0, 1, -1, 1, -1 };
int dy[8] = { 0, 0, 1, -1, 1, -1, -1, 1 };
//#include "Lynia.h"
namespace MyTools
{
template <typename T>
class Math;
template <const int T>
class ModInt;
}
namespace MT = MyTools;
using Math = MT::Math<ll>;
#define geo MT::Geo
const int mod = 1e9 + 7;
using mint = MT::ModInt<mod>;
const int N = 1e6 + 10;
int ask(int x, int y) {
cout << "? " << x << ' ' << y << endl;
cout.flush();
int res; cin >> res;
return res;
}
void answer(int x) {
cout << "! " << x << endl;
cout.flush();
}
void solve(int CASE)
{
int n; cin >> n;
var g = vector<vector<int>>(n + 1, vector<int>());
fa(i, 1, n) {
int x, y; cin >> x >> y;
if (x)g[i].pb(x), g[x].pb(i);
if (y)g[i].pb(y), g[y].pb(i);
}
// 获取重心
int root = 0; // 重心
int now_n = n; // 当前子树的大小,因为重心一直会变,原重心会被删,所以得加上这个
var siz = vector<int>(n + 1); // i 的每个子树的大小
var mxsiz = vector<int>(n + 1); // i 的每个子树的大小的最大值
var vis = vector<bool>(n + 1); // 存哪些点已经当过重心用了
mxsiz[0] = IINF; // 找重心用
// 找重心
var getroot = [&](var getroot, int now, int fa)->void {
// 每次遍历整个树的时候都不用刷新 siz/mxsiz 数组,因为每次都会更新
siz[now] = 1; mxsiz[now] = 0;
for (var& to : g[now]) {
if (to == fa or vis[to])continue;
getroot(getroot, to, now);
siz[now] += siz[to]; // 计算 now 作为子树的大小
mxsiz[now] = max(mxsiz[now], siz[to]); // 找 now 的每个子树大小的最大值
}
// 所有子树,包括父节点的
mxsiz[now] = max(mxsiz[now], now_n - siz[now]);
// 看看当前是不是重心
// 要满足 now 的最大子树的大小不能超过 root 的最大子树的大小
if (mxsiz[now] < mxsiz[root])root = now;
};
var dfs = [&](var dfs, int now)->void { // now 为当前重心
vis[now] = 1;
var son = vector<int>();
for (var& to : g[now]) {
if (vis[to])continue;
son.pb(to);
}
// 查询重心的度
if (son.size() == 0)answer(now); // 本身就是答案
else if (son.size() == 1) { // 只有两个点
int res = ask(son[0], now);
if (res == 0)answer(son[0]);
else answer(now);
}
else if (son.size() == 2) { // 直接问两个子树
int res = ask(son[0], son[1]);
if (res == 0) {
root = 0;
mxsiz[0] = IINF;
now_n = siz[son[1]];
getroot(getroot, son[0], now);
dfs(dfs, root);
}
else if (res == 2) {
root = 0;
mxsiz[0] = IINF;
now_n = siz[son[1]];
getroot(getroot, son[1], now);
dfs(dfs, root);
}
else answer(now);
}
else { // 问两个大小较大的子树,因为在中间的自然会多一个节点
sort(all(son), [&](int x, int y)->bool {
return siz[x] > siz[y];
});
int res = ask(son[0], son[1]);
if (res == 0) {
root = 0;
mxsiz[0] = IINF;
now_n = siz[son[0]];
getroot(getroot, son[0], now);
dfs(dfs, root);
}
else if (res == 2) {
root = 0;
mxsiz[0] = IINF;
now_n = siz[son[1]];
getroot(getroot, son[1], now);
dfs(dfs, root);
}
else {
vis[now] = 0;
vis[son[0]] = vis[son[1]] = 1;
root = 0;
mxsiz[0] = IINF;
now_n = siz[now] - siz[son[0]] - siz[son[1]];
getroot(getroot, now, 0);
dfs(dfs, root);
}
}
};
getroot(getroot, 1, 0);
dfs(dfs, root);
return;
}
int main()
{
//SetConsoleOutputCP(CP_UTF8);
//ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _ = 1;
cin >> _;
fa(i, 1, _)solve(i);
return 0;
}
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 100
Accepted
time: 1ms
memory: 3556kb
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
Runtime Error
input:
5555 8 2 0 8 6 0 0 3 0 0 0 7 0 0 0 5 4 0 2 0 8 0 0 1 4 2 0 0 0 7 8 0 0 3 0 6 0 2 1 2 8 5 8 0 0 1 7 0 0 0 0 4 2 0 0 6 0 0 0 0 5 4 5 3 1 0 0 0 0 0 0 1 0 8 0 0 0 0 5 6 0 0 1 4 2 0 3 8 0 0 0 0 5 3 0 5 1 0 0 0 0 4 0 2 0 5 5 0 0 0 0 0 3 0 2 4 1 2 3 3 0 1 0 0 0 1 2 2 0 0 0 2 3 2 3 0 0 0 0 2 10 2 8 9 7 0 0 ...
output:
? 2 4 ? 1 6 ? 6 7 ! 6 ? 5 3 ? 3 1 ? 2 4 ! 4 ? 1 6 ? 1 7 ? 1 5 ! 1 ? 2 4 ? 1 5 ! 1 ? 5 6 ? 1 4 ! 1 ? 5 1 ? 3 1 ! 3 ? 1 4 ? 5 2 ! 2 ? 3 2 ! 1 ? 1 2 ! 2 ? 2 3 ! 3 ? 2 6 ? 1 9 ? 9 10 ! 9 ? 1 2 ! 1 ? 5 9 ? 3 5 ! 3