真的是我第一次打不是板题的三维偏序。。。
打得我精疲力尽要死要活。。。
\(Solution\)
我们尝试将树上问题转化成一个平面内的问题。我们先按时间排序。
对于添加一个点对,我们可以看成在\((dfn[x]\)$ed[x],dfn[y]$\(ed[y])\)这个矩阵当中加\(1\)。
到时候查询的时候只需要查询两个点\((dfn[x],dfn[y])\)和\((dfn[y],dfn[x])\)即可。
而对于矩阵加\(1\)可以分成两个不同\(x\)的\(+1\)和\(-1\),相当于差分。
我们只需要在\(CDQ\)分治的时候搞成\(x\)排序的即可。
然后在分治后处理合并问题的时候左区间做修改,右区间查询即可。
用一个数据结构来维护一下\(y\)坐标的答案值即可。
有一点小细节需要注意:
对于添加一个矩阵\([x1\)$x2,y1$\(y2]\),我们分成的是\(x1\)的和\(x2+1\)的。
对于当前区间中只有某次操作的\(-1\),而这次操作的\(+1\)在左边的区间内的话。
由于到时候合并的时候右边区间的操作不需要进行修改,所以到时候还是会加回去的,值不变。
\(Code\)
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 400010
#define ll long long
#define lowbit(x) (x & (-x))
#define mem(x, a) memset(x, a, sizeof x)
#define mpy(x, y) memcpy(x, y, sizeof y)
#define fo(x, a, b) for (int x = (a); x <= (b); x++)
#define fd(x, a, b) for (int x = (a); x >= (b); x--)
#define go(x) for (int p = tail[x], v; p; p = e[p].fr)
using namespace std;
struct ask{int ti, x, yl, yr, pl;}q[N << 2], c[N << 2];
struct node{int v, fr;}e[N << 1];
int n, m, Q, tail[N], cnt = 0, fa[N][17], aw[N];
int ord[N], dfn[N], ed[N], tot = 0, dep[N], hav_ans = 1;
int t[N];
inline int read() {
int x = 0, f = 0; char c = getchar();
while (c < '0' || c > '9') f = (c == '-') ? 1 : f, c = getchar();
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return f ? -x : x;
}
inline void add(int u, int v) {e[++cnt] = (node){v, tail[u]}; tail[u] = cnt;}
void dfs(int x) {
for (int i = 0; fa[fa[x][i]][i]; i++)
fa[x][i + 1] = fa[fa[x][i]][i];
dfn[++tot] = x, ord[x] = tot;
go(x) {
if ((v = e[p].v) == fa[x][0]) continue;
dep[v] = dep[x] + 1, fa[v][0] = x, dfs(v);
}
ed[x] = tot;
}
int calc_(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
fd(i, 16, 0) if (dep[x] - (1 << i) > dep[y]) x = fa[x][i];
return x;
}
void modify(int x, int pl) {for (int i = x; i <= n; i += lowbit(i)) t[i] += pl;}
int query(int x) {int s = 0; for (int i = x; i; i -= lowbit(i)) s += t[i]; return s;}
void CDQ(int l, int r) {
if (l == r) return;
int mid = (l + r) >> 1;
CDQ(l, mid), CDQ(mid + 1, r);
int le = l, ri = mid + 1, now_ = l;
// fo(i, 1, n) t[i] = 0;
while (now_ <= r) {
if (le <= mid && (ri > r || q[le].x <= q[ri].x)) {
c[now_] = q[le], now_++;
if (q[le].pl != 1 && q[le].pl != -1) {le++; continue;}
modify(q[le].yl, q[le].pl), modify(q[le].yr + 1, -q[le].pl), le++;
}
else {
c[now_] = q[ri], now_++;
if (q[ri].pl == 1 || q[ri].pl == -1) {ri++; continue;}
aw[q[ri].pl] += query(q[ri].yr); ri++;
}
}
fo(i, l, mid) {
if (q[i].pl != 1 && q[i].pl != -1) continue;
modify(q[i].yl, -q[i].pl), modify(q[i].yr + 1, q[i].pl);
}
fo(i, l, r) q[i] = c[i];
return;
}
int main()
{
freopen("letter.in", "r", stdin);
freopen("letter.out", "w", stdout);
n = read(), m = read(), Q = read();
fo(i, 2, n) {
int u = read(), v = read();
add(u, v), add(v, u);
}
dfs(1); tot = 0;
fo(i, 1, m) {
int x = read(), y = read(), nd = calc_(x, y);
if (ord[x] > ord[y]) swap(x, y);
if (fa[nd][0] == x) {
q[++tot] = (ask){1, 1, ord[y], ed[y], +1};
q[++tot] = (ask){1, ord[nd], ord[y], ed[y], -1};
q[++tot] = (ask){1, ed[nd] + 1, ord[y], ed[y], +1};
q[++tot] = (ask){1, n + 1, ord[y], ed[y], -1};
}
else {
q[++tot] = (ask){1, ord[x], ord[y], ed[y], +1};
q[++tot] = (ask){1, ed[x] + 1, ord[y], ed[y], -1};
}
}
fo(i, 1, Q) {
int opt = read(), x = read(), y = read();
if (ord[x] > ord[y]) swap(x, y);
if (opt == 1) {
q[++tot] = (ask){i + 1, ord[x], ord[y], ord[y], ++hav_ans};
q[++tot] = (ask){i + 1, ord[y], ord[x], ord[x], hav_ans};
}
else {
int nd = calc_(x, y);
if (fa[nd][0] == x) {
q[++tot] = (ask){i + 1, 1, ord[y], ed[y], +1};
q[++tot] = (ask){i + 1, ord[nd], ord[y], ed[y], -1};
q[++tot] = (ask){i + 1, ed[nd] + 1, ord[y], ed[y], +1};
q[++tot] = (ask){i + 1, n + 1, ord[y], ed[y], -1};
}
else {
q[++tot] = (ask){i + 1, ord[x], ord[y], ed[y], +1};
q[++tot] = (ask){i + 1, ed[x] + 1, ord[y], ed[y], -1};
}
}
}
/*
fo(i, 1, tot) printf("%d %d %d %d\n", q[i].x, q[i].yl, q[i].yr, q[i].pl);
return 0;
*/
CDQ(1, tot);
fo(i, 2, hav_ans) printf("%d\n", aw[i]);
return 0;
}