CF757G Can Bash Save the Day?(可持久化边分治)

CF757G Can Bash Save the Day?(可持久化边分治)

题目大意

一棵 \(n\) 个点的树和一个排列 \(p_i\) ,边有边权,支持两种操作:

  • \(l\ r\ x\),询问 \(\sum\limits _{i=l}^{r} dis(p_i,x)\)
  • \(x\),交换 \(p_x,p_{x+1}\)

数据范围

\(n,q\leq 2\times 10^5\),强制在线

解题思路

牛逼题

显然这是一道老经典题了,考虑开店那题,直接动态点分治上整个前缀和,二分查找即可

考虑有修改,每个点整个平衡树或者动态开点线段树即可,都是 \(\Theta(n\log^2n)\) 的,其中第一个做法常数大,第二个做法空间大,都过不去

还有另外一种思路,考虑所有距离和等于 \(\sum (dep_x+dep_y)-2*\sum dep_{lca(x,y)}\)

前面那个很好求,后面那个考虑树链剖分,可以想象为先把 y 到根的链打上标记,然后从 x 跳到根路径上的标记长度就是 \(dep_{lca(x,y)}\),具体来说打标记的方式可以维护每一条边被覆盖的次数,然后乘上整体的区间长度即可,把线段树换成主席树标记永久化即可实现静态,考虑如何交换相邻两项,由于是和的形式,容易发现后面一项一直到最后一项的主席树没有变化,只需要把第 x 个主席树重构一下即可,但显然这个做法虽然常数小了一点,但时间复杂度和空间复杂度还是爆炸的

考虑边分治这种神仙做法,边分治可以可持久化!当然点分治也可以但是比边分治要麻烦一些吧

可以看看暴力写挂那题,边分树是可以合并的,那么也意味着它可以支持可持久化,就像线段树一样

每个点当叶子都可以取出一条从根(边分治的根)到它的链,我们取出待用,取原题排列一个,按顺序将所有链轻轻合并,查询时用第 r 棵边分树减去第 l - 1 边分树的答案即可,交换相邻两项时直接重构前一棵主席边分树即可

我们边分树真的是太厉害了

经检验,代码可读

const int N = 500500;
struct Tree {
	int ls, rs;
	ll vl, vr, sl, sr;
	#define sl(p) tree[p].sl
	#define sr(p) tree[p].sr
	#define ls(p) tree[p].ls
	#define rs(p) tree[p].rs
	#define vl(p) tree[p].vl
	#define vr(p) tree[p].vr
}tree[N * 32];

int rt[N], nodecnt, cnt, n, q;
namespace Conquer {
	const int N = 1500050;
	int h[N], ne[N<<1], to[N<<1], w[N<<1], tot = 1;
	inline void add(int x, int y, int z) {
		ne[++tot] = h[x], to[h[x] = tot] = y, w[tot] = z;
	}
	int Siz, siz[N], vis[N], las[N], lim, ed;
	inline void adde(int x, int y, int z) { 
		add(x, y, z), add(y, x, z); 
//		write(x, ' '), write(y, ' '), write(z); 
	}
	
	void get(int x, int fa) {
		siz[x] = 1;
		for (int i = h[x], y; i; i = ne[i]) {
			if ((y = to[i]) == fa || vis[i]) continue;
			get(y, x), siz[x] += siz[y];
			int tp = max(siz[y], Siz - siz[y]);
			if (tp < lim) lim = tp, ed = i;
		}
	}
	
	void dfs(int x, int fa, ll Dis, int ty) {
		if (x <= n) {
			++nodecnt, !rt[x] && (rt[x] = nodecnt);
			if (ls(las[x]) == -1) ls(las[x]) = nodecnt;
			else rs(las[x]) = nodecnt;
			if (!ty) ls(nodecnt) = -1, vl(nodecnt) = Dis, sl(nodecnt)++;
			else rs(nodecnt) = -1, vr(nodecnt) = Dis, sr(nodecnt)++;
			las[x] = nodecnt;
		}
		for (int i = h[x], y; i; i = ne[i])
			if ((y = to[i]) != fa && !vis[i])
				dfs(y, x, Dis + w[i], ty);
	}
	
	void conquer(int x, int S) {
		if (S <= 1) return;
		Siz = lim = S, get(x, 0), vis[ed] = vis[ed ^ 1] = 1;
		int tx = to[ed], ty = to[ed ^ 1];
//		write(tx, ' '), write(ty);
		dfs(tx, 0, 0, 0), dfs(ty, 0, w[ed], 1);
		conquer(ty, S - siz[tx]), conquer(tx, siz[tx]);
	}
}

int h[N], ne[N<<1], to[N<<1], w[N<<1], las[N], tot;
inline void add(int x, int y, int z) {
	ne[++tot] = h[x], to[h[x] = tot] = y, w[tot] = z;
}

void dfs(int x, int fa) {
	for (int i = h[x], y; i; i = ne[i]) {
		if ((y = to[i]) == fa) continue; dfs(y, x);
		if (!las[x]) Conquer::adde(las[x] = x, y, w[i]);
		else {
			Conquer::adde(las[x], ++cnt, 0);
			Conquer::adde(las[x] = cnt, y, w[i]);
		}
	}
}

int update(int pre, int nw) {
	int rt = ++nodecnt; tree[rt] = tree[pre];
	vl(rt) += vl(nw), vr(rt) += vr(nw), sl(rt) += sl(nw), sr(rt) += sr(nw);
	if (sl(nw) > 0) ls(rt) = update(ls(rt), ls(nw));
	if (sr(nw) > 0) rs(rt) = update(rs(rt), rs(nw));
	return rt;
}

ll query(int nw, int p1, int p2) {
	if (sl(nw) > 0) 
		return query(ls(nw), ls(p1), ls(p2)) + vr(p2) - vr(p1) + (sr(p2) - sr(p1)) * vl(nw);
	if (sr(nw) > 0) 
		return query(rs(nw), rs(p1), rs(p2)) + vl(p2) - vl(p1) + (sl(p2) - sl(p1)) * vr(nw);
	return 0;
}

const int B = (1 << 30) - 1;
ll ans, T[N], p[N];
int main() {
	read(n), read(q), cnt = n;
	for (int i = 1;i <= n; i++) read(p[i]);
	for (int i = 1, x, y, z;i < n; i++)
		read(x), read(y), read(z), add(x, y, z), add(y, x, z);
	dfs(1, 0), Conquer::conquer(1, cnt), tree[0] = tree[nodecnt+10];
	for (int i = 1;i <= nodecnt; i++) Mx(ls(i), 0), Mx(rs(i), 0);
	for (int i = 1;i <= n; i++) T[i] = update(T[i-1], rt[p[i]]);
	while (q--) {
		ll op, x, y, z; read(op);
		if (op == 1) {
			read(x), read(y), read(z);
			x = ans ^ x, y ^= ans, z ^= ans;
			write(ans = query(rt[z], T[x - 1], T[y]));
			ans &= B;
		}
		else {
			read(x), x ^= ans, swap(p[x], p[x+1]);
			T[x] = update(T[x-1], rt[p[x]]);
		}
	}
	return 0;
}

posted @ 2020-07-23 14:48  Hs-black  阅读(317)  评论(0编辑  收藏  举报