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