「IOI2021」地牢游戏 题解
Solution
我们将 \(z\) 按 \([2^i,2^{i+1})\) 划分成 \(\log2(n)\) 层,那么对于 \(z\) 和 \(s_x\) 处于同一层的情况,如果 \(z\ge s_x\),那么 \(z\to 2\times s_x\),就会进入下一层,所以最多只有 \(\log\) 次这类操作。
对于不在同一层的情况,那么我们根据两者所在层就可以判断大小关系,所以我们不需要记录 \(z\) 的具体值,就可以一层单独处理,但是我们需要保证加上值之后不会超过该层,但是你发现这个东西只需要开始时 \(\le\) 某个值即可,这个值也可以处理出来,所以我们就可以直接倍增处理一层信息。
这样我们就可以做到 \((n+q)\log^2 v\) 。不过据说可以按 \([k^i,k^{i+1})\) ,但是有点难写,所以我就咕掉了。
Code
#include "dungeons.h"
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define ll long long
#define MAXN 400005
#define LOGN 19
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}
ll git[LOGN][MAXN][LOGN];
int n,q,lg2,upt,s[MAXN],w[MAXN],p[MAXN],l[MAXN],pos[LOGN][MAXN][LOGN],lim[LOGN][MAXN][LOGN];//lim[k][i][j]表示在第i层走2^j布不超过该层的限制
void Init (){
int mxv = 0;
for (Int i = 1;i <= n;++ i) chkmax (mxv,s[i]);
lg2 = log2 (mxv);
for (Int t = 0;t <= lg2;++ t){
int up = (1 << t + 1) - 1;
for (Int i = 1;i <= n;++ i){
if (s[i] < (1 << t)) git[t][i][0] = s[i],pos[t][i][0] = w[i],lim[t][i][0] = up - s[i];
else git[t][i][0] = p[i],pos[t][i][0] = l[i],lim[t][i][0] = max (0,min (up - p[i],s[i] - 1));
}
pos[t][n + 1][0] = n + 1;
for (Int j = 1;j <= lg2;++ j)
for (Int i = 1;i <= n + 1;++ i)
pos[t][i][j] = pos[t][pos[t][i][j - 1]][j - 1],
git[t][i][j] = git[t][i][j - 1] + git[t][pos[t][i][j - 1]][j - 1],
lim[t][i][j] = max (0ll,min (1ll * lim[t][i][j - 1],lim[t][pos[t][i][j - 1]][j - 1] - git[t][i][j - 1]));
}
int t = lg2 + 1;
for (Int i = 1;i <= n;++ i) pos[t][i][0] = w[i],git[t][i][0] = s[i];
pos[t][n + 1][0] = n + 1,upt = log2 (n);
for (Int j = 1;j <= upt;++ j)
for (Int i = 1;i <= n + 1;++ i)
pos[t][i][j] = pos[t][pos[t][i][j - 1]][j - 1],
git[t][i][j] = git[t][i][j - 1] + git[t][pos[t][i][j - 1]][j - 1];
}
ll Query (int x,int Z){
++ x;ll z = Z;
for (Int t = log2(z);t <= lg2;++ t){
for (Int i = lg2;~i;-- i) if (z <= lim[t][x][i])
z += git[t][x][i],x = pos[t][x][i];
if (x == n + 1) break;
if (s[x] < (1 << t) || z >= s[x]) z += s[x],x = w[x];
else if (z < s[x]) z += p[x],x = l[x];
}
if (x != n + 1){
int t = lg2 + 1;
for (Int i = upt;~i;-- i) if (pos[t][x][i] != n + 1) z += git[t][x][i],x = pos[t][x][i];
z += git[t][x][0],x = pos[t][x][0];
}
return z;
}
#define poly vector<int>
void init (int N,poly S,poly P,poly W,poly L){
n = N;
for (Int i = 1;i <= n;++ i) s[i] = S[i - 1];
for (Int i = 1;i <= n;++ i) p[i] = P[i - 1];
for (Int i = 1;i <= n;++ i) w[i] = W[i - 1] + 1;
for (Int i = 1;i <= n;++ i) l[i] = L[i - 1] + 1;
Init ();
}
ll simulate (int x, int z){
return Query (x + 1,z);
}