P5360 [SDOI2019] 世界地图
超级好的题!
首先考虑一下
而原问题需要我们合并前后缀,发现合并复杂度爆了。发现我们实际上并没有利用到网格图的性质,当我们在处理后缀的时候,我们断的边不可能是一条连着的点都不是最左边一列中的点的边,这启发我们动态维护最左边一列的点建的虚树,这样子复杂度就可以控制在
那么我们对于前后缀分别做一次每次查询合并就好了,时间复杂度
代码:
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i (l); i <= (r); ++ i)
#define rrp(i, l, r) for (int i (r); i >= (l); -- i)
#define eb emplace_back
#define pii pair <int, int>
#define inf 1000000000
#define ls (p << 1)
#define rs (ls | 1)
using namespace std;
constexpr int N = 1e4 + 5, M = 105, P = 1e9 + 7;
typedef long long ll;
typedef unsigned long long ull;
inline int rd () {
int x = 0, f = 1;
char ch = getchar ();
while (! isdigit (ch)) {
if (ch == '-') f = -1;
ch = getchar ();
}
while (isdigit (ch)) {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar ();
}
return x * f;
}
int qpow (int x, int y, int p = P) {
int ret = 1;
for (; y; y >>= 1, x = x * x % p) if (y & 1) ret = ret * x % p;
return ret;
}
int n, m, lim;
unsigned int SA, SB, SC;
inline int read()
{
SA ^= SA << 16;
SA ^= SA >> 5;
SA ^= SA << 1;
ll t = SA;
SA = SB;
SB = SC;
SC ^= t ^ SA;
return SC % lim + 1;
}
int a[N][M], b[N][M];
int is[N * M];
class EDG {
public:
int u, v, w;
friend bool operator < (const EDG &a, const EDG &b) {
return a.w < b.w;
}
};
class MST {
public:
vector <EDG> e;
int tot; ll sum;
void init (int * a) {
tot = n; sum = 0;
rep (i, 1, n - 1) e.eb ((EDG) {i, i + 1, a[i]});
}
ll qry () {
ll ret (sum);
for (auto p : e) ret += p.w;
return ret;
}
} pre[N], suf[N];
int fa[N];
vector <pii> g[N];
int find (int x) {
return x == fa[x] ? x : fa[x] = find (fa[x]);
}
bool dfs (int u, int fa) {
int s (0);
for (auto p : g[u]) if (p.first ^ fa) s += dfs (p.first, u);
is[u] |= s >= 2;
return s | is[u];
}
vector <EDG> e;
ll sum;
void dfs (int u, int fa, int zu, int mx) {
if (is[u]) {
if (zu) e.eb ((EDG) {is[u], zu, mx});
sum -= mx, mx = 0; zu = is[u];
}
for (auto p : g[u]) if (p.first ^ fa) dfs (p.first, u, zu, max (mx, p.second));
}
MST merge (MST a, MST b, int * c) {
MST ret;
e.clear ();
for (auto p : a.e) e.eb (p);
for (auto p : b.e) e.eb ((EDG) {p.u + a.tot, p.v + a.tot, p.w});
rep (i, 1, n) e.eb ((EDG) {a.tot + i - n, a.tot + i, c[i]});
sort (e.begin (), e.end ());
rep (i, 1, a.tot + b.tot) {
fa[i] = i;
is[i] = (i <= n || i > a.tot + b.tot - n);
g[i].clear ();
}
sum = 0;
for (auto p : e) {
int u (p.u), v (p.v), w (p.w);
if (find (u) ^ find (v)) {
g[u].eb (pii (v, w)), g[v].eb (pii (u, w));
fa[find (u)] = v; sum += w;
}
} dfs (1, 0);
int cnt (0);
rep (i, 1, a.tot + b.tot) {
if (is[i]) is[i] = ++ cnt;
} e.clear ();
dfs (1, 0, 0, 0);
ret.tot = cnt; ret.sum = a.sum + b.sum + sum, ret.e = e;
return ret;
}
int32_t main () {
// freopen ("1.in", "r", stdin);
// freopen ("1.out", "w", stdout);
scanf ("%d%d%u%u%u%d", &n, &m, &SA, &SB, &SC, &lim);
rep (i, 1, n) rep (j, 1, m) a[j][i] = read ();
rep (i, 1, n - 1) rep (j, 1, m) b[j][i] = read ();
rep (i, 1, m) pre[i].init (b[i]), suf[i].init (b[i]);
rep (i, 2, m - 1) pre[i] = merge (pre[i - 1], pre[i], a[i - 1]);
rrp (i, 2, m - 1) suf[i] = merge (suf[i], suf[i + 1], a[i]);
for (int q (rd ()); q; -- q) {
int L (rd ()), R (rd ());
printf ("%lld\n", merge (suf[R + 1], pre[L - 1], a[m]).qry ());
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?