题目大意
现在要求可持久地维护一个字符集大小为
M
字符串
解题思路
首先要知道的是对于一个字符串
S
,它的最小循环节的长度为最大的
然后我们发现题目实际上要求我们维护一颗
Trie
,并且对于每条到根的链维护出
next
数组。那么复杂度肯定会有问题。那么我们考虑一样另一种方式维护这个东西。设
T(x,y)
表示在
x
到根的路径上,如果下一个字符为
那么考虑
程序
//YxuanwKeith
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 3e5 + 5;
struct Node {
int l, r, Num;
} Tr[MAXN * 20];
int tot, Ans, N, M, Ord, Fa[MAXN][20], Len[MAXN], Root[MAXN], A[MAXN];
int Query(int Rt, int l, int r, int Side) {
if (!Rt) return 0;
if (l == r) return Tr[Rt].Num;
int Mid = (l + r) >> 1;
if (Side <= Mid) return Query(Tr[Rt].l, l, Mid, Side); else
return Query(Tr[Rt].r, Mid + 1, r, Side);
}
void Modify(int &Rt, int rt, int l, int r, int Side, int Poi) {
Rt = ++ tot;
Tr[Rt] = Tr[rt];
if (l == r) {
Tr[Rt].Num = Poi;
return;
}
int Mid = (l + r) >> 1;
if (Side <= Mid) Modify(Tr[Rt].l, Tr[rt].l, l, Mid, Side, Poi); else
Modify(Tr[Rt].r, Tr[rt].r, Mid + 1, r, Side, Poi);
}
int main() {
scanf("%d%d%d", &N, &M, &Ord);
for (int i = 1; i <= N; i ++) {
int u, c;
scanf("%d%d", &u, &c);
if (Ord == 1) u ^= Ans, c ^= Ans;
A[i] = c;
Fa[i][0] = u;
for (int j = 1; j < 20; j ++) Fa[i][j] = Fa[Fa[i][j - 1]][j - 1];
Len[i] = Len[u] + 1;
int Side = Query(Root[u], 1, M, c);
Ans = Len[i] - Len[Side];
printf("%d\n", Ans);
int p = i, Up = Ans - 1;
for (int j = 19; j + 1; j --)
if (Len[i] - Len[Fa[p][j]] <= Up) p = Fa[p][j];
Modify(Root[i], Root[Side], 1, M, A[p], p);
}
}