住所
解決
以下のための\(1 \のLeq I \のLeq M \) 、別々に前処理された経度と考え\([1、I] \)、\ ([I、M] \)点(\ \テキスト{MST} \ ) 。複合クエリ場合\([1、L-1 ] \) と\([R + 1、M ] \) へ。
どのように前処理考える\([1、i]は\ ) の\(\テキストMST} {\)(\ ([I、M] \)と同様)。
我々が持っていると仮定\([1、I-1 ] \) の(テキストMST} {\ \)\今経度を追加し、\(I \)点とエッジの数。
エッジを追加することを検討((U、V、W \ )\) 何が起こりますか:
\(1 \) \(U、V \)接続されていない場合、接続\(U、V \) 。
\(2 \) \(U、V \)が連通されており、パス\(U→V \)最大側(\ \のLeq W \) 、何も起こりません。
\(3 \) \(Uは、V \)が連通されており、パス\(U→V \)最大側\(> W \) 、この最大エッジは、接続を切断\(U、V \) 。
すなわち、([1 ,. 1-I] \)\の(\ \テキスト{MST} \ ) の縁の一部が削除されてもよいです。我々\(\テキスト{MST} \ ) における最初の列と最後の点が臨界点と呼ばれ、その後、エッジが削除された\(Lが\)を満足しなければならない:臨界点の存在\(X、Y \)ように\(L \)パスである(X→Y \)\最大側の重量。
すなわち、経度内のエンドポイントで\([1、I-1 ] \) すべてのエッジの切れ(\ \テキストkruscalを} {\) 。エッジ\(L \)接続二つの通信ブロックは、2つのブロックが通信鍵がある場合、次に\(Lは\)を削除してもよい、または\(L \)を削除することはできません。
そう記録エッジ設定すること\(pre_iが\)経度を表し\([1、i]の\ ) 点(\ \テキスト{MST} \ ) 側が削除されてもよいした後に、。
\([1、I-1 ] \) の\(\テキスト{MST} \ ) 、NOT IN \(pre_ {I-1} \) エッジ(必ずエッジの後に削除されない)確かである\ ([1、i]は\)の\(\テキスト{MST} \ ) です。仮定(pre_ {I-1} \ \) キーポイントの端部側である限り、我々\(pre_ {I-1} \) と、新たに追加された(2N-1 \)\ストリップテイク一緒になくなった(\テキストkruscal} {\)\、肯定的な結果は、一緒に消去されていないエッジである([1、i]を\ \ ) の\(\テキストMST} {\) 。
しかし、\(pre_ {I-1} \) エンドポイント側はそれを行う方法を、必ずしも重要なポイントではありませんか?
検討\(\テキスト\ {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);
仮定({I-1} \ \ pre_) キーポイントは、その後得られるの側面を考慮することができる(pre_i \)\:
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 \)がある(pre_ {I-1} \ \) を加えた新たな\(2N-1 \)エッジ、\(1 bo_x = \)を表す\(Xを\)、キーポイントである(\ B \)です\(pre_i \) 。
このように、我々が得る\(pre_i \)、\ (suf_i \)共感を。
問い合わせ\((L、R&LT)\) 、限り、\(pre_ {L-1} \) と\(suf_ {R + 1} \) 公知の方法を用いて、マージされ\(pre_ {I-1 } \)を求める\(pre_i \)ほとんど。
時間複雑\(O(NM \ N-ログ)\) 。
コード
#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;
}