【LCT】CSP 202109-5 箱根山岳险天下 LCT维护时间树
今天上完了人生最后一节化学课,泪目😭,完结撒花🌸
这道题容易感觉是主席树but不是,因为操作仍然是对现在的点操作,问的答案也不是问历史答案而是现在的答案。
我们以排名为树的高度,就很容易想到一棵以时间为序依次加点的树。对于删点就等于在时间上退到父亲,然后之后就在父亲的基础下再加点。
如果可以离线那么我们树剖维护,but在线那么改成LCT就可以了。
#include <bits/stdc++.h>
using namespace std;
int MOD;
int ad(int x, int y) {
x += y;
return x >= MOD ? x - MOD : x;
}
int mu(int x, int y) { return 1ll * x * y % MOD; }
const int maxn = 3e5 + 5;
int ch[maxn][2], fa[maxn], fa_tru[maxn]; // lct fa actually fa
int sm[maxn], tot, A[maxn], rev[maxn], dep[maxn], lz[maxn];
vector<pair<int, int>> BC[maxn];
static bool isroot(int p) { return ch[fa[p]][0] != p && ch[fa[p]][1] != p; }
void putup(int p) { sm[p] = ad(ad(sm[ch[p][0]], sm[ch[p][1]]), A[p]); }
void rotate(int x) {
int y = fa[x];
int z = fa[y];
fa[x] = z;
if (!isroot(y)) {
ch[z][ch[z][1] == y] = x;
}
int k = (ch[y][1] == x);
ch[y][k] = ch[x][k ^ 1];
fa[ch[y][k]] = y;
fa[y] = x;
ch[x][k ^ 1] = y;
putup(y);
putup(x);
}
void pushdown(int p) {
if (rev[p]) {
swap(ch[p][0], ch[p][1]);
rev[ch[p][0]] ^= 1, rev[ch[p][1]] ^= 1;
rev[p] = 0;
}
if (lz[p] != 1) {
A[ch[p][0]] = mu(A[ch[p][0]], lz[p]);
A[ch[p][1]] = mu(A[ch[p][1]], lz[p]);
sm[ch[p][0]] = mu(sm[ch[p][0]], lz[p]);
sm[ch[p][1]] = mu(sm[ch[p][1]], lz[p]);
lz[ch[p][0]] = mu(lz[ch[p][0]], lz[p]);
lz[ch[p][1]] = mu(lz[ch[p][1]], lz[p]);
lz[p] = 1;
}
}
void splay(int x) {
int y, z;
static int sta[maxn], top;
top = 0;
sta[++top] = x;
for (int i = x; !isroot(i); i = fa[i]) {
sta[++top] = fa[i];
}
while (top)
pushdown(sta[top--]);
while (!isroot(x)) {
y = fa[x];
z = fa[y];
if (!isroot(y))
(ch[z][0] == y) ^ (ch[y][0] == x) ? rotate(x) : rotate(y);
rotate(x);
}
}
void acc(int x) {
for (int y = 0; x; y = x, x = fa[x]) {
splay(x);
ch[x][1] = y;
putup(x);
}
}
void setroot(int x) {
acc(x);
splay(x);
rev[x] ^= 1;
}
void link(int x, int y) {
setroot(x);
fa[x] = y;
}
int getp(int tim, int rank) {
auto it = --upper_bound(BC[rank].begin(), BC[rank].end(),
make_pair(tim, 0x3f3f3f3f));
return it->second;
}
int M, T, NOW, LA;
int main() {
scanf("%d%d%d", &M, &MOD, &T);
int OPT, S, L, R, Y;
for (int tim = 1; tim <= M; tim++) {
scanf("%d%d", &OPT, &S);
if (OPT == 1) {
if (T)
S = (S ^ LA);
if (S == 0) {
NOW = fa_tru[NOW];
} else {
++tot;
lz[tot] = 1;
fa_tru[tot] = fa[tot] = NOW;
dep[tot] = dep[NOW] + 1;
BC[dep[tot]].push_back(make_pair(tim, tot));
A[tot] = sm[tot] = S;
NOW = tot;
}
} else if (OPT == 2) {
scanf("%d%d%d", &L, &R, &Y);
if (T)
Y = Y ^ LA;
L = getp(S, L); // S 天 第L名
R = getp(S, R);
setroot(L);
acc(R);
splay(R);
A[R] = mu(A[R], Y);
sm[R] = mu(sm[R], Y);
lz[R] = mu(lz[R], Y);
} else {
scanf("%d%d", &L, &R);
L = getp(S, L);
R = getp(S, R);
setroot(L), acc(R), splay(R);
LA = sm[R];
printf("%d\n", LA);
}
}
return 0;
}