Live2D

「IOI2021」地牢游戏 题解

link

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);
}
posted @ 2022-01-24 15:18  Dark_Romance  阅读(206)  评论(0编辑  收藏  举报