LOJ #2092. 「ZJOI2016」大森林(lct)
题解:
-
因为保证询问合法,所以可以把询问放到最后去询问
-
0操作可以视作对\([1,n]\)的树都操作,但是在1操作时,因为没有\(x\)的树不换生长节点,所以要和对应0操作的区间取交。
-
设1操作的区间取交是[l,r],若从左往右考虑每个树,发现\(tree[l]\)和\(tree[l-1]\)的区别就是把之前生长节点的子树复制到\(x\)下面,r同理。
-
所以不难想到ETT暴力维护,但是可以建虚点,把一个生长节点的子树放到它的虚点下,虚点再指向它,这样就可以用lct维护了。
-
注意到两个点的lca可能是一个虚点,这可能会对答案产生影响,因此lct要不换根的以求lca。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
const int N = 4e5 + 5;
int n, m;
int td, tt;
int op, x, y, z;
int L[N], R[N];
#define pii pair<int, int>
#define pb push_back
#define si size()
namespace lct {
int t[N][2], fa[N], pf[N], s[N], z[N];
#define x0 t[x][0]
#define x1 t[x][1]
int lr(int x) { return t[fa[x]][1] == x;}
void upd(int x) {
s[x] = z[x] + s[x0] + s[x1];
}
void ro(int x) {
int y = fa[x], k = lr(x);
t[y][k] = t[x][!k]; if(t[x][!k]) fa[t[x][!k]] = y;
fa[x] = fa[y]; if(fa[y]) t[fa[y]][lr(y)] = x;
fa[y] = x, t[x][!k] = y, pf[x] = pf[y];
upd(y); upd(x);
}
void sp(int x, int y) {
for(; fa[x] != y; ro(x)) if(fa[fa[x]] != y)
ro(lr(x) == lr(fa[x]) ? fa[x] : x);
}
void ac(int x) {
int xx = x;
for(int y = 0; x; ) {
sp(x, 0), fa[x1] = 0, pf[x1] = x;
x1 = y, fa[y] = x, pf[y] = 0;
upd(x), y = x, x = pf[x];
}
sp(xx, 0);
}
void link(int x, int y) {
ac(x); pf[x] = y;
}
void cut(int x) {
ac(x);
int y = x0;
fa[y] = x0 = 0;
upd(x);
}
int lca(int u, int v) {
ac(u);
int la = v;
for(int x = v, y = 0; x; ) {
sp(x, 0), fa[x1] = 0, pf[x1] = x;
x1 = y, fa[y] = x, pf[y] = 0;
upd(x), y = x, x = pf[x];
if(x) la = x;
}
return la;
}
int findv(int x) {
ac(x);
return s[x];
}
int qry(int u, int v) {
int w = lca(u, v);
return findv(u) + findv(v) - 2 * findv(w) + 1;
}
}
struct nod {
int x, y, z;
};
vector<nod> e[N], q[N];
int q0;
void Init() {
scanf("%d %d", &n, &m);
fo(i, 1, m) lct :: z[i] = lct :: z[i] = 1;
L[1] = 1, R[1] = n;
td = 1; tt = m + 2;
int la = tt;
lct :: link(la, 1);
fo(i, 1, m) {
scanf("%d %d %d", &op, &x, &y);
if(op == 0) {
td ++;
L[td] = x, R[td] = y;
lct :: link(td, la);
} else
if(op == 1) {
scanf("%d", &z);
x = max(x, L[z]);
y = min(y, R[z]);
if(x > y) continue;
tt ++;
lct :: link(tt, la);
e[x].pb((nod) {tt, la, z});
e[y + 1].pb((nod) {tt, z, la});
la = tt;
} else {
scanf("%d", &z);
q0 ++;
q[x].pb((nod) {y, z, q0});
}
}
}
int ans[N];
void End() {
fo(i, 1, n) {
ff(_j, 0, e[i].si) {
nod a = e[i][_j];
lct :: cut(a.x);
lct :: link(a.x, a.z);
}
ff(_j, 0, q[i].si) {
nod a = q[i][_j];
ans[a.z] = lct :: qry(a.x, a.y);
}
}
fo(i, 1, q0) pp("%d\n", ans[i] - 1);
}
int main() {
Init();
End();
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址