P9361 [ICPC2022 Xi'an R] Contests 题解
under_the_time · · 题解
update on 2025-11-20
注意到我 2023 年写的题解有点不知所云,因此进行重构。感谢管理审核 'w'
题意
给定
m 个1\sim n 的排列p_1,p_2,\cdots,p_m ,令q_{i,j} 表示第i 个元素在p_j 中的排名,Q 次询问,每次给定x,y ,求出最小的l ,使得存在两个长度为l+1 的序列\set{b_i},\set{c_i} ,使得b_1=x,b_{l+1}=y 并且\forall i\in[1,l]\cap \Z,q_{b_i,c_i}<q_{b_{i+1},c_{i+1}} ;或者报告无解。
题解
对于一组询问
注意到合法的
意思就是把
每一轮倍增先算
对于一次询问,倍增过程中维护当前
代码
#include <bits/stdc++.h>
bool MemoryST; using namespace std;
#define ll long long
#define mk make_pair
#define open(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define lowbit(x) ((x) & (-(x)))
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define BCNT __builtin_popcount
#define cost_time (1e3 * clock() / CLOCKS_PER_SEC) << "ms"
#define cost_space (abs(&MemoryST - &MemoryED) / 1024.0 / 1024.0) << "MB"
const int inf = 0x3f3f3f3f;
const ll linf = 1e18;
mt19937 rnd(random_device{}());
template<typename T> void chkmax(T& x, T y) { x = max(x, y); }
template<typename T> void chkmin(T& x, T y) { x = min(x, y); }
template<typename T> T abs(T x) { return (x < 0) ? -x : x; }
const int maxn = 1e5 + 5, maxm = 10;
int n, Q, m; int p[maxm][maxn], rnk[maxn][maxm];
int f[maxn][20][maxm], h[maxm][maxn][20][maxm];
int t[maxm], nxt[maxm];
bool vld(int y) {
for (int i = 1; i <= m; i ++) if (nxt[i] <= rnk[y][i]) return 1;
return 0;
}
bool MemoryED; int main() {
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; i ++)
for (int j = 1; j <= n; j ++) scanf("%d", &p[i][j]), rnk[p[i][j]][i] = j;
for (int i = 1; i <= n; i ++) for (int j = 1; j <= m; j ++) f[i][0][j] = rnk[i][j];
for (int i = 0; i <= 18; i ++) {
for (int k = 1; k <= m; k ++)
for (int u = 1; u <= m; u ++) {
for (int v = n; v; v --)
h[u][v][i][k] = min(v == n ? inf : h[u][v + 1][i][k], f[p[u][v]][i][k]);
}
if (i == 18) break;
for (int x = 1; x <= n; x ++)
for (int k = 1; k <= m; k ++) {
f[x][i + 1][k] = inf;
for (int j = 1; j <= m; j ++) chkmin(f[x][i + 1][k], h[j][f[x][i][j]][i][k]);
}
} scanf("%d", &Q);
for (int _ = 1, x, y; _ <= Q; _ ++) {
scanf("%d %d", &x, &y); int ans = 0; bool beg = 0, ok = 0;
for (int i = 18; ~i; i --) {
if (!beg) for (int j = 1; j <= m; j ++) nxt[j] = f[x][i][j];
else for (int j = 1; j <= m; j ++) {
nxt[j] = inf;
for (int k = 1; k <= m; k ++) chkmin(nxt[j], h[k][t[k]][i][j]);
} if (vld(y)) ok = 1;
else { ans += (1 << i), beg = 1; for (int j = 1; j <= m; j ++) t[j] = nxt[j]; }
} if (!ok) puts("-1");
else printf("%d\n", ans + 1);
}
return 0;
}