本题要求构造一棵满足特定度数限制的无根树。关键观察是:若存在三度节点,则其应有三个子节点,其余内部节点均为二度节点,所有叶子节点为一度点。
构造策略如下:
- 先将所有一度点分配给三度节点(每个三度节点最多分3个)。
- 若三度节点总数加上额外需连接的点超过一度点总数,则无解。
- 特殊情况处理:当三度点为0且一度点为3时,无法构成有效树;若剩余一度点为1,也无法完成连接。
最终新增一个中心节点,将剩余的一度点全部连到该节点上。整个结构通过模拟构建边集输出。
题目要求找到最小的"最大边权乘以路径长度"的值,使得从起点1能到达终点n。
核心思想:使用二分答案,判断是否存在一条路径,其总代价不超过当前枚举值。
算法设计:
- 用 BFS 模拟路径扩展,记录每个点经过的边数 `dis[u]`。
- 对于每条边 `(u,v)`,若 `(dis[u] + 1) * w ≤ mid` 且未访问过 `v`,则更新 `dis[v]`。
- 注意:环的存在不影响判断,因为只要能到达终点即可,无需考虑路径唯一性。
问题本质是在图中选择一组边,使得最终每个点的度数奇偶性满足某种目标状态。
解法步骤:
1. 首先对原图求最大生成树(按边编号降序),原因在于:不被选中的边应尽量编号小,以减少修改次数。
2. 在树上进行奇偶调整:定义"翻转"操作(改变某条边是否被选)。
3. 使用可持久化并查集维护每条边的翻转状态。对于每条边,向上查找其父边,若路径上存在翻转影响,则整体标记。
4. 从虚拟节点0开始,沿最小编号路径递归翻转,实现最优策略。
关键点:不能路径压缩,并查集需支持回溯和版本控制。
解决在线查询矩形覆盖面积的问题。核心思想是:
- 离线处理:对坐标离散化,按横坐标扫描。
- 维护纵坐标区间内"未被覆盖"的时间总和。
- 使用可持久化线段树支持历史版本查询。
- 查询时将区间拆分为若干完整块与边界部分,利用前后版本差值估算。
时间复杂度:$O(n \log n)$,空间优化可通过永久化标记降低常数。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int maxm = 3e7;
vector<int> sx, sy;
struct Segment {
struct Node {
int mn, mncnt, ls, rs;
int del, tag;
i64 mnsum;
} a[maxm];
struct info {
int mn, mncnt; i64 mnsum;
friend info operator + (info x, info y) {
info z;
z.mn = min(x.mn, y.mn); z.mnsum = x.mnsum + y.mnsum;
if (x.mn < y.mn) z.mncnt = x.mncnt;
else if (x.mn > y.mn) z.mncnt = y.mncnt;
else z.mncnt = x.mncnt + y.mncnt;
return z;
}
info apply(int del, int tag, int is) {
return {mn + del, mncnt, mnsum + (mn + del == is ? 1LL * tag * mncnt : 0)};
}
};
int cnt;
inline int newnode(int u) {
int cur = ++cnt;
assert(cnt < maxm - 10);
a[cur] = a[u];
return cur;
}
inline void seta(int u, int del, int tag, int is) {
a[u].del += del;
a[u].mn += del;
if (a[u].mn == is) {
a[u].mnsum += 1LL * a[u].mncnt * tag;
a[u].tag += tag;
}
}
inline void dw(int u) {
a[u].ls = newnode(a[u].ls);
seta(a[u].ls, a[u].del, a[u].tag, a[u].mn);
a[u].rs = newnode(a[u].rs);
seta(a[u].rs, a[u].del, a[u].tag, a[u].mn);
a[u].del = a[u].tag = 0;
}
inline void up(int u) {
a[u].mn = min(a[a[u].ls].mn, a[a[u].rs].mn);
if (a[a[u].ls].mn < a[a[u].rs].mn) a[u].mncnt = a[a[u].ls].mncnt;
else if (a[a[u].ls].mn > a[a[u].rs].mn) a[u].mncnt = a[a[u].rs].mncnt;
else a[u].mncnt = a[a[u].ls].mncnt + a[a[u].rs].mncnt;
}
void update(int &u, int l, int r, int ql, int qr, int k) {
u = newnode(u);
if (l >= ql && r <= qr) return seta(u, k, 0, 0);
int mid = l + r >> 1; dw(u);
if (qr <= mid) update(a[u].ls, l, mid, ql, qr, k);
else if (ql > mid) update(a[u].rs, mid + 1, r, ql, qr, k);
else update(a[u].ls, l, mid, ql, qr, k), update(a[u].rs, mid + 1, r, ql, qr, k);
up(u);
}
info query(int u, int l, int r, int ql, int qr) {
if (l >= ql && r <= qr) return info{a[u].mn, a[u].mncnt, a[u].mnsum};
int mid = l + r >> 1;
if (qr <= mid) return query(a[u].ls, l, mid, ql, qr).apply(a[u].del, a[u].tag, a[u].mn);
else if (ql > mid) return query(a[u].rs, mid + 1, r, ql, qr).apply(a[u].del, a[u].tag, a[u].mn);
else return (query(a[u].ls, l, mid, ql, qr) + query(a[u].rs, mid + 1, r, ql, qr)).apply(a[u].del, a[u].tag, a[u].mn);
}
void build(int &u, int l, int r) {
u = newnode(0);
if (l == r) {
a[u].mncnt = sy[l + 1] - sy[l];
return;
}
int mid = l + r >> 1;
build(a[u].ls, l, mid), build(a[u].rs, mid + 1, r);
up(u);
}
} ds;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int r, c, n, q;
cin >> r >> c >> n >> q;
vector<array<int, 4>> mat(n);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < 4; ++j) cin >> mat[i][j];
if (mat[i][0] == mat[i][2] || mat[i][1] == mat[i][3]) {
i--; n--;
continue;
}
if (mat[i][0] > mat[i][2]) swap(mat[i][0], mat[i][2]);
if (mat[i][1] > mat[i][3]) swap(mat[i][1], mat[i][3]);
sx.push_back(mat[i][0]), sx.push_back(mat[i][2]);
sy.push_back(mat[i][1]), sy.push_back(mat[i][3]);
}
sx.push_back(-1), sy.push_back(-1);
sx.push_back(r + 1), sy.push_back(c + 1);
sort(sx.begin(), sx.end()), sx.erase(unique(sx.begin(), sx.end()), sx.end());
sort(sy.begin(), sy.end()), sy.erase(unique(sy.begin(), sy.end()), sy.end());
vector<vector<array<int, 3>>> upd(sx.size());
vector<int> rt(sx.size());
for (int i = 0; i < n; ++i) {
for (int j = 0; j < 4; ++j) {
if (j & 1) mat[i][j] = lower_bound(sy.begin(), sy.end(), mat[i][j]) - sy.begin();
else mat[i][j] = lower_bound(sx.begin(), sx.end(), mat[i][j]) - sx.begin();
}
upd[mat[i][0]].push_back({mat[i][1], mat[i][3] - 1, 1});
upd[mat[i][2]].push_back({mat[i][1], mat[i][3] - 1, -1});
}
ds.build(rt[0], 0, sy.size() - 2);
for (int i = 1; i < sx.size(); ++i) {
rt[i] = rt[i - 1];
ds.seta(rt[i], 0, sx[i] - sx[i - 1], 0);
for (auto& u : upd[i]) ds.update(rt[i], 0, sy.size() - 2, u[0], u[1], u[2]);
}
i64 lstans = 0;
for (int i = 0; i < q; ++i) {
int x1, x2, y1, y2;
i64 v;
cin >> x1 >> y1 >> x2 >> y2 >> v;
x1 = (x1 + (__int128)v * lstans) % (r + 1);
x2 = (x2 + (__int128)v * lstans) % (r + 1);
y1 = (y1 + (__int128)v * lstans) % (c + 1);
y2 = (y2 + (__int128)v * lstans) % (c + 1);
if (x1 == x2 || y1 == y2) {
cout << (lstans = 0) << '\n';
continue;
}
if (x1 > x2) swap(x1, x2);
if (y1 > y2) swap(y1, y2);
int u1 = lower_bound(sx.begin(), sx.end(), x1) - sx.begin();
int u2 = upper_bound(sx.begin(), sx.end(), x2) - sx.begin() - 1;
int v1 = lower_bound(sy.begin(), sy.end(), y1) - sy.begin();
int v2 = upper_bound(sy.begin(), sy.end(), y2) - sy.begin() - 1;
auto calcy = [&](int u1, int u2) {
auto calc = [&](int v1, int v2) {
return ds.query(rt[u2], 0, sy.size() - 2, v1, v2).mnsum -
(u1 ? ds.query(rt[u1 - 1], 0, sy.size() - 2, v1, v2).mnsum : 0);
};
if (v1 > v2) {
return calc(v2, v2) / (sy[v1] - sy[v2]) * (y2 - y1);
} else {
i64 ans = (sy[v1] - y1 ? calc(v1 - 1, v1 - 1) / (sy[v1] - sy[v1 - 1]) * (sy[v1] - y1) : 0) +
(y2 - sy[v2] ? calc(v2, v2) / (sy[v2 + 1] - sy[v2]) * (y2 - sy[v2]) : 0);
if (v1 < v2) ans += calc(v1, v2 - 1);
return ans;
}
};
if (u1 > u2) {
i64 ans = calcy(u2, u2) / (sx[u1] - sx[u2]) * (x2 - x1);
cout << (lstans = 1LL * (x2 - x1) * (y2 - y1) - ans) << '\n';
} else {
i64 ans = (sx[u1] - x1 ? calcy(u1 - 1, u1 - 1) / (sx[u1] - sx[u1 - 1]) * (sx[u1] - x1) : 0) +
(x2 - sx[u2] ? calcy(u2, u2) / (sx[u2 + 1] - sx[u2]) * (x2 - sx[u2]) : 0);
if (u1 < u2) ans += calcy(u1, u2 - 1);
cout << (lstans = 1LL * (x2 - x1) * (y2 - y1) - ans) << '\n';
}
}
return 0;
}