题目链接
(代码在最后)
这个点只需要读懂题目就能乱搞过去。
无数种方法中的一个:
依次修改 0 ≤ i < n − 1 0\leq i<n-1 0≤i<n−1,依次查询 i < j < n i<j<n i<j<n 并记录,假如 j j j 相比上次有变化,代表它与 i i i 有边。
由 M = N / 2 M=N/2 M=N/2 和性质 A 可以看出所有点是一对一对的。
再看 L m , L q L_m,L_q Lm,Lq,发现它们大概是 O ( n log n ) O(n\log n) O(nlogn) 的。所以我们考虑 n log n n\log n nlogn 的方法。
二分?分治?排序? log \log log 数据结构?
这道题(我采用的)其实是二进制位。
枚举编号的每个二进制位,修改这一位为 1 的所有节点。接着查询所有节点,我们根据这个节点编号在这个二进制位上的值分类讨论,可以得到与其配对的节点的编号在这位上的值。
假如不想记录每一次的查询结果的话,在每一位求完后直接把修改过的节点改回去即可。
这是一棵父节点编号小于子节点的树。
我们考虑类似上一个 Subtask 的做法,但是按编号从小到大枚举时一边修改,一边查询,这样每个节点在被查询到时只会受其父亲影响。
最后得到每个节点(0 除外)的父亲编号,挨个输出即可。
这是一条链。
模仿上上个 subtask 的方法,我们可以得到与其连接的两个节点的异或和。
接着修改 0 号点,再 O ( n ) O(n) O(n) 扫一遍找到与 0 连接的2(1)个点。接着从这两个点入手就可以求出来了。
咕咕咕
LOJ 格式化后的代码:
#include "explore.h"
#include
#include
#include
#include
namespace my_exp_2_5 {
bool li[510];
}
namespace my_exp_6_9 {
int p[200000];
}
namespace my_exp_10_11 {
int p[200000];
}
namespace my_exp_12_14 {
int p[200000];
}
void explore(int N, int M) {
if (N == 3 && M == 2) {
modify(0);
int q1 = query(1), q2 = query(2);
if (q1)
report(0, 1);
if (q2)
report(0, 2);
if (q1 != q2)
report(1, 2);
return;
}
if (N <= 500 && N % 10 == 0) {
using namespace my_exp_2_5;
for (int i = 0; i < N - 1; i++) {
modify(i);
for (int j = i + 1; j < N; j++) {
int q = query(j);
if (q != li[j]) {
report(i, j);
li[j] = q;
}
}
}
return;
}
if (N % 10 == 8) {
using namespace my_exp_6_9;
for (int i = 0; (1 << i) <= N; i++) {
for (int j = 0; j < N; j++) {
if (!((j >> i) & 1))
continue;
modify(j);
}
for (int j = 0; j < N; j++) {
if ((j >> i) & 1) {
p[j] |= ((!query(j)) << i);
} else {
p[j] |= (query(j) << i);
}
}
for (int j = 0; j < N; j++) {
if (!((j >> i) & 1))
continue;
modify(j);
}
}
for (int i = 0; i < N; i++) {
if (p[i] < i)
report(i, p[i]);
}
return;
}
if (N % 10 == 7) {
using namespace my_exp_10_11;
for (int i = 0; (1 << i) <= N; i++) {
for (int j = 0; j < N; j++) {
p[j] |= (query(j) << i);
if ((j >> i) & 1)
modify(j);
}
for (int j = 0; j < N; j++) {
if ((j >> i) & 1)
modify(j);
}
}
for (int i = 1; i < N; i++) {
report(i, p[i]);
}
return;
}
if (N % 10 == 6) {
using namespace my_exp_12_14;
for (int i = 0; (1 << i) <= N; i++) {
for (int j = 0; j < N; j++) {
if (!((j >> i) & 1))
continue;
modify(j);
}
for (int j = 0; j < N; j++) {
if ((j >> i) & 1) {
p[j] |= ((!query(j)) << i);
} else {
p[j] |= (query(j) << i);
}
}
for (int j = 0; j < N; j++) {
if (!((j >> i) & 1))
continue;
modify(j);
}
}
modify(0);
int c1 = 0, c2 = 0;
for (int i = 1; i < N; i++) {
if (query(i)) {
if (c1)
c2 = i;
else
c1 = i;
}
}
int last = 0, now = c1;
for (int i = 1; i < N; i++) {
report(last, now);
if (check(now))
break;
last = (last ^ p[now]);
int t = last;
last = now;
now = t;
}
if (c2) {
last = 0, now = c2;
for (int i = 1; i < N; i++) {
report(last, now);
if (check(now))
break;
last = (last ^ p[now]);
int t = last;
last = now;
now = t;
}
}
return;
}
}