码迷,mamicode.com
首页 > 其他好文 > 详细

[CF1486F] Pairs of Paths

时间:2021-03-06 15:03:23      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:dep   std   else   pair   continue   strong   去掉   情况   bit   

Problem

给定一棵树和若干个点对 \((u,v)\) 给出的树上最短路径,求满足 路径交仅有一个点无序 路径对(即 \((a,b)\)\((b,a)\) 算一次)。

Sol & Code

交仅为一个点只有两种情况:两条路径 LCA 在同一个点或不在同一个点。

技术图片

分别计算。第一种使用容斥:交一个点、两个点、三个点加加减减;第二种较为简单,无需考虑交三个点的情况。注意要去掉两种情况之间的影响。复杂度 \(\mathcal O(n\log n)\)

#include <bits/stdc++.h>
using std::vector; using std::swap;
typedef long long LL;
const int N = 300005;
int n, m;
struct Edge { int v, nxt; } e[N * 2];
int G[N * 2], edges = 0;
void adde(int u, int v) {
	e[edges++] = (Edge){v, G[u]}; G[u] = edges - 1;
}
int fa[19][N], dep[N];
void dfs(int u, int f) {
	dep[u] = dep[f] + 1; fa[0][u] = f;
	for (int i = 1; i < 19; i++) fa[i][u] = fa[i - 1][fa[i - 1][u]];
	for (int i = G[u]; ~i; i = e[i].nxt)
		if (e[i].v != f) dfs(e[i].v, u);
}
void get(int &u, int d) {
	for (int i = 0; d; i++, d >>= 1)
		if (d & 1) u = fa[i][u];
}
int lca(int x, int y) {
	if (dep[x] < dep[y]) swap(x, y);
	get(x, dep[x] - dep[y]);
	if (x == y) return x;
	for (int i = 18; ~i; i--)
		if (fa[i][x] != fa[i][y]) x = fa[i][x], y = fa[i][y];
	return fa[0][x];
}
int sum[N], c[N]; LL ans = 0;
struct node {
	int x, y;
	bool operator < (const node &o) const {
		return x != o.x ? x < o.x : y < o.y;
	}
};
vector<node> tg[N];
void Dfs(int u) {
	for (int i = G[u], v; ~i; i = e[i].nxt) 
		if (v = e[i].v, v != fa[0][u])
			Dfs(v), sum[u] += sum[v];
	c[u] = sum[u] - tg[u].size();
	sort(tg[u].begin(), tg[u].end());
	ans += 1LL * tg[u].size() * c[u];
	for (int i = 0; i < tg[u].size(); i++) {
		if (tg[u][i].x) c[tg[u][i].x]--;
		if (tg[u][i].y) c[tg[u][i].y]--;
	}
	for (int i = 0; i < tg[u].size(); i++) {
		if (tg[u][i].x) ans -= c[tg[u][i].x];
		if (tg[u][i].y) ans -= c[tg[u][i].y];
	}
	LL tot = 0;
	for (int i = G[u], v; ~i; i = e[i].nxt)
		if (v = e[i].v, v != fa[0][u]) c[v] = 0;
	for (int i = 0; i < tg[u].size(); i++) {
		if (tg[u][i].x) c[tg[u][i].x]++;
		if (tg[u][i].y) c[tg[u][i].y]++;
	}
	tot += 1LL * tg[u].size() * tg[u].size();
	for (int l = 0, r = 0; l < tg[u].size(); l = r) {
		while (r < tg[u].size() && tg[u][l].x == tg[u][r].x && tg[u][l].y == tg[u][r].y) r++;
		if (tg[u][l].x) tot -= 1LL * (r - l) * c[tg[u][l].x];
		if (tg[u][l].y) tot -= 1LL * (r - l) * c[tg[u][l].y];
		if (!tg[u][l].x || !tg[u][l].y) continue;
		tot += 1LL * (r - l) * (r - l);
	}
	for (int i = 0; i < tg[u].size(); i++) {
		if (tg[u][i].x || tg[u][i].y) break;
		tot--;
	}
	ans += tot / 2;
}
int main() {
	scanf("%d", &n);
	memset(G, -1, sizeof G);
	for (int i = 1; i < n; i++) {
		int u, v; scanf("%d%d", &u, &v);
		adde(u, v), adde(v, u);
	}
	dfs(1, 0);
	scanf("%d", &m);
	for (int i = 1; i <= m; i++) {
		int u, v, t, x, y; scanf("%d%d", &u, &v); t = lca(u, v);
		if (u == t) x = 0; else x = u, get(x, dep[u] - dep[t] - 1);
		if (v == t) y = 0; else y = v, get(y, dep[v] - dep[t] - 1);
		if (x > y) swap(x, y);
		tg[t].push_back((node){x, y});
		sum[u]++, sum[v]++, sum[t]--, sum[fa[0][t]]--;
	}
	Dfs(1);
	printf("%lld", ans);
	return 0;
}

[CF1486F] Pairs of Paths

标签:dep   std   else   pair   continue   strong   去掉   情况   bit   

原文地址:https://www.cnblogs.com/ac-evil/p/14490076.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!