Address
Solution
对于 1 ≤ i ≤ m 1\leq i\leq m 1≤i≤m,考虑分别预处理经度在 [ 1 , i ] [1,i] [1,i], [ i , m ] [i,m] [i,m] 的点的 MST \text{MST} MST。询问的时候合并 [ 1 , l − 1 ] [1,l-1] [1,l−1] 和 [ r + 1 , m ] [r+1,m] [r+1,m] 即可。
先考虑怎么预处理 [ 1 , i ] [1,i] [1,i] 的 MST \text{MST} MST( [ i , m ] [i,m] [i,m] 同理)。
假设我们已经有了 [ 1 , i − 1 ] [1,i-1] [1,i−1] 的 MST \text{MST} MST,现在要在这里加上经度为 i i i 的点和一些边。
考虑加入一条边 ( u , v , w ) (u,v,w) (u,v,w) 会发生什么:
1.
1.
1.
u
,
v
u,v
u,v 不连通,连接
u
,
v
u,v
u,v。
2.
2.
2.
u
,
v
u,v
u,v 已经连通,且路径
u
→
v
u→v
u→v 的边的最大值
≤
w
\leq w
≤w,什么也不会发生。
3.
3.
3.
u
,
v
u,v
u,v 已经连通,且路径
u
→
v
u→v
u→v 的边的最大值
>
w
> w
>w,断开这条最大边,连接
u
,
v
u,v
u,v。
也就是说, [ 1 , i − 1 ] [1,i-1] [1,i−1] 的 MST \text{MST} MST 中可能会有一些边被删掉。我们把 MST \text{MST} MST 中第一列和最后一列的点称为关键点,那么被删掉的边 l l l 必定满足:存在关键点 x , y x,y x,y 使得 l l l 是路径 x → y x→y x→y 上的权值最大边。
换句话说,把端点的经度在 [ 1 , i − 1 ] [1,i-1] [1,i−1] 的边全部拿出来跑 kruscal \text{kruscal} kruscal。边 l l l 会连接两个连通块,如果这两个连通块里面都有关键点,那么 l l l 可能被删掉,否则 l l l 不可能被删掉。
因此记录边集 p r e i pre_i prei 表示经度在 [ 1 , i ] [1,i] [1,i] 的点的 MST \text{MST} MST 中,之后可能被删的边。
[ 1 , i − 1 ] [1,i-1] [1,i−1] 的 MST \text{MST} MST 中,不在 p r e i − 1 pre_{i-1} prei−1 的边(之后肯定不会被删的边)肯定都在 [ 1 , i ] [1,i] [1,i] 的 MST \text{MST} MST 中。 假设 p r e i − 1 pre_{i-1} prei−1 中的边的端点都是关键点,那么我们只要把 p r e i − 1 pre_{i-1} prei−1 和新加入的 2 n − 1 2n-1 2n−1 条边一起拿出来跑 kruscal \text{kruscal} kruscal,所得结果加上肯定不会被删的边,就是 [ 1 , i ] [1,i] [1,i] 的 MST \text{MST} MST。
可是 p r e i − 1 pre_{i-1} prei−1 的边的端点不一定都是关键点,怎么办呢?
考虑 kruscal \text{kruscal} kruscal 的过程:
int fu = find(u), fv = find(v);
if (fu != fv) 在 MST 中加入边 (u, v, w);
其实和这样是等价的:
int fu = find(u), fv = find(v);
if (fu != fv) 在 MST 中加入边 (fu, fv, w);
假设 p r e i − 1 pre_{i-1} prei−1 中的边都是关键点,那么可以考虑这样求出 p r e i pre_i prei:
inline void solve(vector<edge> &a, vector<edge> &b, ll &del)
{
int len = a.size(), i;
sort(a.begin(), a.end(), cmp);
b.clear(); del = 0;
for (i = 0; i < len; i++)
{
int x = a[i].x, y = a[i].y, v = a[i].v, fx = find(x), fy = find(y);
if (fx == fy) del += v;
else
{
if (bo[fx] && bo[fy]) link(fx, fy), b.push_back((edge){fx, fy, v});
// 保证 b 中的边都是关键点
else if (bo[fx]) link(fx, fy);
else link(fy, fx);
}
}
}
其中 a a a 是 p r e i − 1 pre_{i-1} prei−1 加上新的 2 n − 1 2n-1 2n−1 条边, b o x = 1 bo_x=1 box=1 表示 x x x 是关键点, b b b 是 p r e i pre_i prei。
这样我们就得到了 p r e i pre_i prei, s u f i suf_i sufi 同理。
对于询问 ( l , r ) (l,r) (l,r),只要把 p r e l − 1 pre_{l-1} prel−1 和 s u f r + 1 suf_{r+1} sufr+1 合并即可,方法跟已知 p r e i − 1 pre_{i-1} prei−1 求 p r e i pre_i prei 差不多。
时间复杂度 O ( n m log n ) O(nm\log n) O(nmlogn)。
Code
#include <bits/stdc++.h>
using namespace std;
#define ll long long
template <class t>
inline void read(t & res)
{
char ch;
while (ch = getchar(), !isdigit(ch));
res = ch ^ 48;
while (ch = getchar(), isdigit(ch))
res = res * 10 + (ch ^ 48);
}
template <class t>
inline void print(t x)
{
if (x > 9) print(x / 10);
putchar(x % 10 + 48);
}
const int N = 105, M = 10005, T = N * M;
struct edge
{
int x, y, v;
};
vector<edge> pre[M], suf[M];
int n, rht[N][M], dwn[N][M], m, f[T], lim, q;
bool bo[T];
unsigned int SA, SB, SC;
ll pres[M], sufs[M], ans;
// pres[i] 表示 [1,i] 的 MST 的边权之和,sufs[i] 同理
inline int getweight()
{
SA ^= SA << 16;
SA ^= SA >> 5;
SA ^= SA << 1;
unsigned int t = SA;
SA = SB;
SB = SC;
SC ^= t ^ SA;
return SC % lim + 1;
}
inline void gen()
{
read(n); read(m); read(SA); read(SB); read(SC); read(lim);
int i, j;
for (i = 1; i <= n; i++)
for (j = 1; j <= m; j++)
rht[i][j] = getweight();
for (i = 1; i < n; i++)
for (j = 1; j <= m; j++)
dwn[i][j] = getweight();
}
inline int id(int x, int y)
{
return (x - 1) * m + y;
}
inline int find(int x)
{
return f[x] == x ? x : f[x] = find(f[x]);
}
inline bool cmp(const edge &a, const edge &b)
{
return a.v < b.v;
}
inline void link(int x, int y)
{
f[y] = x;
}
inline void upt(int x, bool y)
{
f[x] = x;
bo[x] = y;
}
inline void solve(vector<edge> &a, vector<edge> &b, ll &del)
{
int len = a.size(), i;
sort(a.begin(), a.end(), cmp);
b.clear(); del = 0;
for (i = 0; i < len; i++)
{
int x = a[i].x, y = a[i].y, v = a[i].v, fx = find(x), fy = find(y);
if (fx == fy) del += v;
else
{
if (bo[fx] && bo[fy]) link(fx, fy), b.push_back((edge){fx, fy, v});
else if (bo[fx]) link(fx, fy);
else link(fy, fx);
}
}
}
inline void init_pre()
{
int i, j;
for (i = 1; i <= n * m; i++) f[i] = i;
ll del;
vector<edge> a, b;
for (i = 1; i <= m; i++)
{
for (j = 1; j <= n; j++)
{
upt(id(j, i), 1);
upt(id(j, 1), 1);
if (i > 2) upt(id(j, i - 1), 0);
}
a = pre[i - 1];
pres[i] = pres[i - 1];
for (j = 1; j <= n; j++)
{
if (i != 1)
{
a.push_back((edge){id(j, i - 1), id(j, i), rht[j][i - 1]});
pres[i] += rht[j][i - 1];
}
if (j != n)
{
a.push_back((edge){id(j, i), id(j + 1, i), dwn[j][i]});
pres[i] += dwn[j][i];
}
}
solve(a, b, del);
pre[i] = b;
pres[i] -= del;
}
}
inline void init_suf()
{
int i, j;
ll del;
for (i = 1; i <= n * m; i++) f[i] = i, bo[i] = 0;
vector<edge> a, b;
for (i = m; i >= 1; i--)
{
for (j = 1; j <= n; j++)
{
upt(id(j, i), 1);
upt(id(j, m), 1);
if (i < m - 1) upt(id(j, i + 1), 0);
}
a = suf[i + 1];
sufs[i] = sufs[i + 1];
for (j = 1; j <= n; j++)
{
if (i != m)
{
a.push_back((edge){id(j, i + 1), id(j, i), rht[j][i]});
sufs[i] += rht[j][i];
}
if (j != n)
{
a.push_back((edge){id(j, i), id(j + 1, i), dwn[j][i]});
sufs[i] += dwn[j][i];
}
}
solve(a, b, del);
suf[i] = b;
sufs[i] -= del;
}
}
int main()
{
gen();
init_pre();
init_suf();
int l, r, i;
read(q);
for (i = 1; i <= n * m; i++) f[i] = i, bo[i] = 0;
while (q--)
{
read(l); read(r);
ans = pres[l - 1] + sufs[r + 1];
vector<edge> a, b;
for (i = 1; i <= n; i++)
{
ans += rht[i][m];
a.push_back((edge){id(i, m), id(i, 1), rht[i][m]});
upt(id(i, m), 0);
upt(id(i, 1), 0);
upt(id(i, l - 1), 0);
upt(id(i, r + 1), 0);
}
int len = pre[l - 1].size();
for (i = 0; i < len; i++) a.push_back(pre[l - 1][i]);
len = suf[r + 1].size();
for (i = 0; i < len; i++) a.push_back(suf[r + 1][i]);
ll del = 0;
solve(a, b, del);
ans -= del;
print(ans); putchar('\n');
}
return 0;
}