5.30 杂题选讲
点对#
CodeChef - Minimum Xor Segment#
考虑对于三个数
设
-
当
时,显然 。 -
当
时,显然 。 -
当
是,有用。
我们先随便找一个
每往前找一个
点击查看代码
#include <bits/stdc++.h>
#define ll int
#define fi first
#define se second
#define mkp make_pair//
#define pir pair <ll, ll>
#define pb push_back
using namespace std;
const ll maxn = 2e5 + 10;
ll trie[maxn * 30][2], pos[maxn * 30], tot = 1, n, q;
ll L[maxn], R[maxn], a[maxn];
vector <ll> vec[maxn];
ll tree[maxn];
void add(ll x, ll v) {
while(x <= n) {
tree[x] = min(tree[x], v);
x += x & -x;
}
}
ll ask(ll x) {
ll v = 2e9;
while(x) {
v = min(v, tree[x]);
x ^= x & -x;
}
return v;
}
ll ans[maxn];
int main() {
scanf("%d%d", &n, &q);
memset(tree, 0x3f, sizeof tree);
for(ll i = 1; i <= n; i++)
scanf("%d", a + i);
for(ll i = 1; i <= q; i++) {
scanf("%d%d", L + i, R + i);
vec[R[i]].pb(i);
}
for(ll i = 1; i <= n; i++) {
if(i) add(n - i + 2, a[i] ^ a[i - 1]);
ll p = 1;
for(ll j = 29; ~j; j--) {
ll c = (a[i] >> j) & 1;
if(trie[p][c]) {
p = trie[p][c];
add(n - pos[p] + 1, a[i] ^ a[pos[p]]);
}
else break;
}
for(ll j: vec[i])
ans[j] = ask(n - L[j] + 1);
p = 1;
for(ll j = 29; ~j; j--) {
ll c = (a[i] >> j) & 1;
if(!trie[p][c]) trie[p][c] = ++tot;
p = trie[p][c];
pos[p] = i;
}
}
for(ll i = 1; i <= q; i++)
printf("%d\n", ans[i]);
return 0;
}
倍增分块#
2019ICPC徐州 H - Yuuki and a problem#
考虑值域上倍增分块。具体的,对于
根据神秘数那题的做法,我们从小到大加入数。
对于一个
如果不小于,那么
点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define mkp make_pair
#define pir pair <ll, ll>
#define pb push_back
using namespace std;
const ll maxn = 2e5 + 10, inf = 1e18;
ll n, q, a[maxn];
struct SGT {
ll mn[maxn << 2], sum[maxn << 2];
void modify(ll p, ll l, ll r, ll x, ll v) {
if(l == r) {
if(v == -1) mn[p] = inf, sum[p] = 0;
else mn[p] = sum[p] = v;
return;
}
ll mid = l + r >> 1;
if(x <= mid) modify(p << 1, l, mid, x, v);
else modify(p << 1|1, mid + 1, r, x, v);
mn[p] = min(mn[p << 1], mn[p << 1|1]);
sum[p] = sum[p << 1] + sum[p << 1|1];
}
ll querymn(ll p, ll l, ll r, ll ql, ll qr) {
if(ql <= l && r <= qr) return mn[p];
if(r < ql || qr < l) return inf;
ll mid = l + r >> 1;
return min(querymn(p << 1, l, mid, ql, qr),
querymn(p << 1|1, mid + 1, r, ql, qr));
}
ll querysum(ll p, ll l, ll r, ll ql, ll qr) {
if(ql <= l && r <= qr) return sum[p];
if(r < ql || qr < l) return 0;
ll mid = l + r >> 1;
return querysum(p << 1, l, mid, ql, qr) +
querysum(p << 1|1, mid + 1, r, ql, qr);
}
void build() {
for(ll i = 1; i <= 4 * n; i++)
mn[i] = inf, sum[i] = 0;
}
} tr[18];
ll Log[maxn];
int main() {
scanf("%lld%lld", &n, &q);
for(ll i = 0; i <= 17; i++) tr[i].build();
for(ll i = 2; i <= 2e5; i++) Log[i] = Log[i >> 1] + 1;
for(ll i = 1; i <= n; i++) {
scanf("%lld", a + i);
tr[Log[a[i]]].modify(1, 1, n, i, a[i]);
}
while(q--) {
ll op, x, y;
scanf("%lld%lld%lld", &op, &x, &y);
if(op == 1) {
tr[Log[a[x]]].modify(1, 1, n, x, -1);
tr[Log[y]].modify(1, 1, n, x, a[x] = y);
} else {
ll sum = 0;
for(ll i = 0; i <= 17; i++) {
ll tmp = tr[i].querymn(1, 1, n, x, y);
if(sum + 1 < tmp) break;
sum += tr[i].querysum(1, 1, n, x, y);
}
printf("%lld\n", sum + 1);
}
}
return 0;
}
[IOI2021] 地牢游戏#
倍增分块,对于每个
对于血量
考虑倍增,我们在块
对于每个
点击查看代码
#include <bits/stdc++.h>
#define ll int
#define fi first
#define se second
#define mkp make_pair
#define pir pair <ll, ll>
#define pb push_back
using namespace std;
const ll maxn = 4e5 + 10, M = 5, base = 32, K = 23;
const long long inf = 1e18;
struct Bz {
ll to[maxn][25];
long long sum[maxn][25], lim[maxn][25];
} D[6];
ll pw[6], N, S[maxn], W[maxn];
void init(ll n, vector <ll> s, vector <ll> p, vector <ll> w, vector <ll> l) {
pw[0] = 1, N = n;
for(ll i = 1; i <= M; i++) pw[i] = pw[i - 1] * base;
for(ll i = 0; i < N; i++)
S[i] = s[i], W[i] = w[i];
for(ll u = 0; u <= M; u++) {
for(ll i = 0; i < N; i++) {
if(pw[u] > s[i]) {
D[u].to[i][0] = w[i];
D[u].lim[i][0] = inf;
D[u].sum[i][0] = s[i];
} else {
D[u].to[i][0] = l[i];
D[u].lim[i][0] = s[i];
D[u].sum[i][0] = p[i];
}
}
D[u].to[N][0] = -1;
for(ll j = 1; j <= K; j++) {
for(ll i = 0; i <= N; i++) {
ll p = D[u].to[i][j - 1];
if(p == -1 || D[u].to[p][j - 1] == -1) {
D[u].to[i][j] = -1;
continue;
}
D[u].to[i][j] = D[u].to[p][j - 1];
D[u].lim[i][j] = min(D[u].lim[i][j - 1], D[u].lim[p][j - 1] - D[u].sum[i][j - 1]);
D[u].sum[i][j] = D[u].sum[i][j - 1] + D[u].sum[p][j - 1];
}
}
}
}
long long simulate(ll x, ll _z) {
long long z = _z;
for(ll u = 0; u <= M;) {
while(u < M && z >= pw[u + 1]) ++u;
for(ll i = K; ~i; i--)
if(D[u].to[x][i] != -1 && D[u].lim[x][i] > z) {
z += D[u].sum[x][i];
x = D[u].to[x][i];
}
if(x == N) return z;
z += S[x], x = W[x];
}
}
减半报警器#
CF gym104065B - Call Me Call Me#
区间很难维护。
考虑猫树分治,每个区间转化成了一段前缀 + 一段后缀。
我们把一个区间的
当第
当一个位置上挂的数
这样一个区间的
包括鬼界那题也是这个思想
出处:https://www.cnblogs.com/Sktn0089/p/18223671
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步