6813. 【2020.10.05提高组模拟】送信

真的是我第一次打不是板题的三维偏序。。。
打得我精疲力尽要死要活。。。

(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
", q[i].x, q[i].yl, q[i].yr, q[i].pl);
	return 0;
	*/
	CDQ(1, tot);
	fo(i, 2, hav_ans) printf("%d
", aw[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/jz929/p/13807752.html