[UOJ#407/LOJ#2865][IOI2018]狼人(Kruskal 重构树 + 倍增 + 主席树)

Address

BZOJ4899
UOJ#407
LOJ#2865

Solution

  • 先考虑转化一下问题
  • 询问四个参数 S S E E L L R R
  • 等价于一个图 G 1 G_1 ,它只包含原图中节点编号 L \ge L 的点和这些点之间的边
  • 另一个图 G 2 G_2 ,只包含原图中节点编号 R \le R 的点和这些点之间的边
  • 询问是否存在一个点 u u
  • 满足点 u u 既在 G 1 G_1 S S 所在的连通块内
  • 又在 G 2 G_2 E E 所在的连通块内
  • Kruskal 重构树可以在图持续加边时维护历史版本的连通块信息
  • 即把连通块映射成子树
  • 基本思想就是合并两个连通块时,新建一个点 u u
  • 让这两个连通块对应子树的根作为 u u 的子节点
  • 而如果要找到点 u u 在第 k k 次连边之后所在的连通块
  • 就只需要找到点 u u 的祖先中,深度最小且连通时间 k \le k 的点
  • 可以使用树上倍增实现
  • 回到原问题
  • 发现一个小问题:需要维护连通次序的是点而不是边
  • 但其实只需要令历史版本 i i 表示编号 i \le i i \ge i )的点以及它们之间连的边即可
  • 建立两棵重构树 T 1 T_1 T 2 T_2
  • T 1 T_1 的历史版本 i i 表示编号 i \le i 的点以及它们之间连的边
  • T 2 T_2 的历史版本 i i 表示编号 i \ge i 的点以及它们之间连的边
  • 问题转化为是否存在一个点 u u
  • 既在 T 1 T_1 的某个点的子树内
  • 又在 T 2 T_2 的某个点的子树内
  • 即求 T 1 T_1 的 DFS 序列的某个区间内,是否存在一个点 u u
  • 使得 u u T 2 T_2 中的 DFS 序在某个区间内
  • 主席树实现
  • 复杂度 O ( ( N + M + Q ) log ( N + M + Q ) ) O((N+M+Q)\log (N+M+Q))

Code

  • 完整程序 in luogu
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
#define Edge(u) for (int e = adj[u], v = go[e]; e; e = nxt[e], v = go[e])
#define Tree1(u) for (int e = adj1[u], v = go1[e]; e; e = nxt1[e], v = go1[e])
#define Tree2(u) for (int e = adj2[u], v = go2[e]; e; e = nxt2[e], v = go2[e])

inline int read()
{
	int res = 0; bool bo = 0; char c;
	while (((c = getchar()) < '0' || c > '9') && c != '-');
	if (c == '-') bo = 1; else res = c - 48;
	while ((c = getchar()) >= '0' && c <= '9')
		res = (res << 3) + (res << 1) + (c - 48);
	return bo ? ~res + 1 : res;
}

const int N = 2e5 + 5, Z = N << 1, M = N << 2, E = N * 3, LogN = 21,
L = 1e7 + 5;

int n, m, q, ecnt, nxt[M], adj[N], go[M], Xin[Z], Yin[Z], ToTin, ToTde,
Xde[Z], Yde[Z], maxin[E], maxde[E], fa[E], ancin[E][LogN], ancde[E][LogN],
Tin, Tde, ecnt1, nxt1[E], adj1[E], go1[E], ecnt2, nxt2[E], adj2[E], go2[E],
dfnin[E], dfnde[E], szein[E], szede[E], rt[E], ToT;

struct node
{
	int lc, rc, sum;
} T[L];

void ins(int y, int &x, int l, int r, int p)
{
	T[x = ++ToT] = T[y]; T[x].sum++;
	if (l == r) return;
	int mid = l + r >> 1;
	if (p <= mid) ins(T[y].lc, T[x].lc, l, mid, p);
	else ins(T[y].rc, T[x].rc, mid + 1, r, p);
}

void emptys(int y, int &x)
{
	T[x = ++ToT] = T[y];
}

int sumorz(int y, int x, int l, int r, int s, int e)
{
	if (l == s && r == e) return T[x].sum - T[y].sum;
	int mid = l + r >> 1;
	if (e <= mid) return sumorz(T[y].lc, T[x].lc, l, mid, s, e);
	else if (s >= mid + 1) return sumorz(T[y].rc, T[x].rc, mid + 1, r, s, e);
	else return sumorz(T[y].lc, T[x].lc, l, mid, s, mid)
		+ sumorz(T[y].rc, T[x].rc, mid + 1, r, mid + 1, e);
}

void add_edge(int u, int v)
{
	nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;
	nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u;
}

void add_edge1(int u, int v)
{
	nxt1[++ecnt1] = adj1[u]; adj1[u] = ecnt1; go1[ecnt1] = v;
}

void add_edge2(int u, int v)
{
	nxt2[++ecnt2] = adj2[u]; adj2[u] = ecnt2; go2[ecnt2] = v;
}

int cx(int x)
{
	if (fa[x] != x) fa[x] = cx(fa[x]);
	return fa[x];
}

void zm(int x, int y)
{
	int ix = cx(x), iy = cx(y);
	if (ix != iy) fa[iy] = ix;
}

void dfsin(int u)
{
	dfnin[u] = ++Tin;
	szein[u] = 1;
	Tree1(u) dfsin(v), szein[u] += szein[v];
}

void dfsde(int u)
{
	dfnde[u] = ++Tde;
	if (u <= n) ins(rt[Tde - 1], rt[Tde], 1, Tin, dfnin[u]);
	else emptys(rt[Tde - 1], rt[Tde]);
	szede[u] = 1;
	Tree2(u) dfsde(v), szede[u] += szede[v];
}

int findin(int u, int x)
{
	int i;
	Rof (i, 20, 0)
		if (ancin[u][i] && maxin[ancin[u][i]] <= x)
			u = ancin[u][i];
	return u;
}

int findde(int u, int x)
{
	int i;
	Rof (i, 20, 0)
		if (ancde[u][i] && maxde[ancde[u][i]] >= x)
			u = ancde[u][i];
	return u;
}

int main()
{
	int i, j, x, y, l, r;
	n = read(); m = read(); q = read();
	while (m--) x = read() + 1, y = read() + 1,
		add_edge(x, y);
	m = 0;
	For (i, 1, n)
	{
		Edge(i) if (v < i)
			Xin[++m] = i, Yin[m] = v;
		maxin[i] = m;
	}
	m = 0;
	Rof (i, n, 1)
	{
		Edge(i) if (v > i)
			Xde[++m] = i, Yde[m] = v;
		maxde[i] = m;
	}
	For (i, 1, n) maxde[fa[i] = i] = 0;
	ToTin = ToTde = n;
	For (i, 1, m)
	{
		int u = cx(Xin[i]), v = cx(Yin[i]);
		if (u == v) continue;
		ancin[u][0] = ++ToTin; ancin[v][0] = ToTin;
		maxin[ToTin] = Xin[i];
		fa[ToTin] = ToTin;
		zm(ToTin, u); zm(ToTin, v);
	}
	For (i, 1, n) maxde[fa[i] = i] = n + 1;
	For (i, 1, m)
	{
		int u = cx(Xde[i]), v = cx(Yde[i]);
		if (u == v) continue;
		ancde[u][0] = ++ToTde; ancde[v][0] = ToTde;
		maxde[ToTde] = Xde[i];
		fa[ToTde] = ToTde;
		zm(ToTde, u); zm(ToTde, v);
	}
	Rof (i, ToTin, 1) For (j, 0, 19)
		ancin[i][j + 1] = ancin[ancin[i][j]][j];
	Rof (i, ToTde, 1) For (j, 0, 19)
		ancde[i][j + 1] = ancde[ancde[i][j]][j];
	For (i, 1, ToTin) if (ancin[i][0])
		add_edge1(ancin[i][0], i);
	For (i, 1, ToTde) if (ancde[i][0])
		add_edge2(ancde[i][0], i);
	For (i, 1, ToTin) if (!ancin[i][0]) dfsin(i);
	For (i, 1, ToTde) if (!ancde[i][0]) dfsde(i);
	while (q--)
	{
		x = read() + 1; y = read() + 1;
		l = read() + 1; r = read() + 1;
		int u = findde(x, l), v = findin(y, r);
		puts(sumorz(rt[dfnde[u] - 1], rt[dfnde[u] + szede[u] - 1],
			1, ToTin, dfnin[v], dfnin[v] + szein[v] - 1) ? "1" : "0");
	}
	return 0;
}
  • 交互
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include "werewolf.h"
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
#define Edge(u) for (int e = adj[u], v = go[e]; e; e = nxt[e], v = go[e])
#define Tree1(u) for (int e = adj1[u], v = go1[e]; e; e = nxt1[e], v = go1[e])
#define Tree2(u) for (int e = adj2[u], v = go2[e]; e; e = nxt2[e], v = go2[e])

inline int read()
{
	int res = 0; bool bo = 0; char c;
	while (((c = getchar()) < '0' || c > '9') && c != '-');
	if (c == '-') bo = 1; else res = c - 48;
	while ((c = getchar()) >= '0' && c <= '9')
		res = (res << 3) + (res << 1) + (c - 48);
	return bo ? ~res + 1 : res;
}

const int N = 2e5 + 5, Z = N << 1, M = N << 2, E = N * 3, LogN = 21,
L = 1e7 + 5;

int n, m, q, ecnt, nxt[M], adj[N], go[M], Xin[Z], Yin[Z], ToTin, ToTde,
Xde[Z], Yde[Z], maxin[E], maxde[E], fa[E], ancin[E][LogN], ancde[E][LogN],
Tin, Tde, ecnt1, nxt1[E], adj1[E], go1[E], ecnt2, nxt2[E], adj2[E], go2[E],
dfnin[E], dfnde[E], szein[E], szede[E], rt[E], ToT;

std::vector<int> ans;

struct node
{
	int lc, rc, sum;
} T[L];

void ins(int y, int &x, int l, int r, int p)
{
	T[x = ++ToT] = T[y]; T[x].sum++;
	if (l == r) return;
	int mid = l + r >> 1;
	if (p <= mid) ins(T[y].lc, T[x].lc, l, mid, p);
	else ins(T[y].rc, T[x].rc, mid + 1, r, p);
}

void emptys(int y, int &x)
{
	T[x = ++ToT] = T[y];
}

int sumorz(int y, int x, int l, int r, int s, int e)
{
	if (l == s && r == e) return T[x].sum - T[y].sum;
	int mid = l + r >> 1;
	if (e <= mid) return sumorz(T[y].lc, T[x].lc, l, mid, s, e);
	else if (s >= mid + 1) return sumorz(T[y].rc, T[x].rc, mid + 1, r, s, e);
	else return sumorz(T[y].lc, T[x].lc, l, mid, s, mid)
		+ sumorz(T[y].rc, T[x].rc, mid + 1, r, mid + 1, e);
}

void add_edge(int u, int v)
{
	nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;
	nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u;
}

void add_edge1(int u, int v)
{
	nxt1[++ecnt1] = adj1[u]; adj1[u] = ecnt1; go1[ecnt1] = v;
}

void add_edge2(int u, int v)
{
	nxt2[++ecnt2] = adj2[u]; adj2[u] = ecnt2; go2[ecnt2] = v;
}

int cx(int x)
{
	if (fa[x] != x) fa[x] = cx(fa[x]);
	return fa[x];
}

void zm(int x, int y)
{
	int ix = cx(x), iy = cx(y);
	if (ix != iy) fa[iy] = ix;
}

void dfsin(int u)
{
	dfnin[u] = ++Tin;
	szein[u] = 1;
	Tree1(u) dfsin(v), szein[u] += szein[v];
}

void dfsde(int u)
{
	dfnde[u] = ++Tde;
	if (u <= n) ins(rt[Tde - 1], rt[Tde], 1, Tin, dfnin[u]);
	else emptys(rt[Tde - 1], rt[Tde]);
	szede[u] = 1;
	Tree2(u) dfsde(v), szede[u] += szede[v];
}

int findin(int u, int x)
{
	int i;
	Rof (i, 20, 0)
		if (ancin[u][i] && maxin[ancin[u][i]] <= x)
			u = ancin[u][i];
	return u;
}

int findde(int u, int x)
{
	int i;
	Rof (i, 20, 0)
		if (ancde[u][i] && maxde[ancde[u][i]] >= x)
			u = ancde[u][i];
	return u;
}

std::vector<int> check_validity(int N, std::vector<int> X, std::vector<int> Y,
std::vector<int> S, std::vector<int> E, std::vector<int> L,
std::vector<int> R)
{
	int i, j, x, y, l, r;
	n = N; m = X.size(); q = S.size();
	For (i, 0, m - 1) add_edge(X[i] + 1, Y[i] + 1);
	m = 0;
	For (i, 1, n)
	{
		Edge(i) if (v < i)
			Xin[++m] = i, Yin[m] = v;
		maxin[i] = m;
	}
	m = 0;
	Rof (i, n, 1)
	{
		Edge(i) if (v > i)
			Xde[++m] = i, Yde[m] = v;
		maxde[i] = m;
	}
	For (i, 1, n) maxde[fa[i] = i] = 0;
	ToTin = ToTde = n;
	For (i, 1, m)
	{
		int u = cx(Xin[i]), v = cx(Yin[i]);
		if (u == v) continue;
		ancin[u][0] = ++ToTin; ancin[v][0] = ToTin;
		maxin[ToTin] = Xin[i];
		fa[ToTin] = ToTin;
		zm(ToTin, u); zm(ToTin, v);
	}
	For (i, 1, n) maxde[fa[i] = i] = n + 1;
	For (i, 1, m)
	{
		int u = cx(Xde[i]), v = cx(Yde[i]);
		if (u == v) continue;
		ancde[u][0] = ++ToTde; ancde[v][0] = ToTde;
		maxde[ToTde] = Xde[i];
		fa[ToTde] = ToTde;
		zm(ToTde, u); zm(ToTde, v);
	}
	Rof (i, ToTin, 1) For (j, 0, 19)
		ancin[i][j + 1] = ancin[ancin[i][j]][j];
	Rof (i, ToTde, 1) For (j, 0, 19)
		ancde[i][j + 1] = ancde[ancde[i][j]][j];
	For (i, 1, ToTin) if (ancin[i][0])
		add_edge1(ancin[i][0], i);
	For (i, 1, ToTde) if (ancde[i][0])
		add_edge2(ancde[i][0], i);
	For (i, 1, ToTin) if (!ancin[i][0]) dfsin(i);
	For (i, 1, ToTde) if (!ancde[i][0]) dfsde(i);
	For (i, 0, q - 1)
	{
		x = S[i] + 1; y = E[i] + 1; l = L[i] + 1; r = R[i] + 1;
		int u = findde(x, l), v = findin(y, r);
		ans.push_back(sumorz(rt[dfnde[u] - 1], rt[dfnde[u] + szede[u] - 1],
			1, ToTin, dfnin[v], dfnin[v] + szein[v] - 1) ? 1 : 0);
	}
	return ans;
}

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/83869067
今日推荐