loj3041 joisc2019 矿物 交互题/分治
https://loj.ac/problem/3041
这题操作数要小于
后面都是对的.最后证明当
#include <bits/stdc++.h>
#include "minerals.h"
#define MOD 1000000007
#define INF 1000000000
#define ll long long
#define pii pair<int, int>
#define iiii pair<int, pii>
#define rep(i, x) for (int(i) = 0; (i) < (x); (i)++)
#define mp make_pair
#define a _A
inline int getint() {
char c = getchar();
int x = 0, p = 1;
while (c <= 32) c = getchar();
if (c == 45)
p = -p, c = getchar();
while (c > 32) x = x * 10 + c - 48, c = getchar();
return x * p;
}
using namespace std;
// ruogu
const int N = 43010;
const double alpha = 0.35;
int n, res, a[N], c;
vector<int> v[N << 5];
bool vis[N];
//
void solve(int l, int r, int k) {
if (r - l <= 0)
return;
if (r - l == 1) {
Answer(a[l] + 1, v[k][0] + 1);
return;
}
int mid = l + (r - l) * alpha;
if (mid == r)
--mid;
if (mid == l)
++mid;
for (int i = l; i < mid; i++) {
res = Query(a[i] + 1);
vis[i] ^= 1;
}
int sl = mid - l, sr = r - mid;
rep(i, v[k].size()) {
if (v[c].size() == sl)
v[c + 1].push_back(v[k][i]);
else if (v[c + 1].size() == sr)
v[c].push_back(v[k][i]);
else {
int tmp = Query(v[k][i] + 1);
if ((tmp != res) ^ vis[l])
v[c].push_back(v[k][i]);
else
v[c + 1].push_back(v[k][i]);
res = tmp;
}
}
int ls = c, rs = c + 1;
c += 2;
solve(l, mid, ls);
solve(mid, r, rs);
}
void Solve(int NN) {
srand(233);
int cnt = 0;
n = NN;
c = 1;
rep(i, 2 * n) {
int tmp = Query(i + 1);
if (tmp != res)
a[cnt++] = i;
else
v[0].push_back(i);
res = tmp;
}
rep(i, n) vis[i] = true;
random_shuffle(a, a + n);
random_shuffle(v[0].begin(), v[0].end());
solve(0, n, 0);
}