矩陣最大 10^6 元素,最多 20 行。支持四種操作(m ≤ 20000):
將二維矩陣按行展平為一維數組:第 i 行第 j 列映射到位置 (i-1)*c + j。子矩陣 (x1,y1,x2,y2) 變為 x2-x1+1 個連續區間 [(i-1)*c+y1, (i-1)*c+y2]。
需同時維護 sum、min、max,且賦值操作優先級高於加法(賦值清除舊加法標記)。
struct Node {
ll sum, mn, mx;
ll add_tag; // 區間加標記
ll set_tag; // 區間賦值標記,-1 表示無
bool has_set() { return set_tag != -1; }
};
class SegTree {
vector t;
int n;
void apply_set(int o, int l, int r, ll v) { ... }
void apply_add(int o, int l, int r, ll v) { ... }
void push_down(int o, int l, int r) { ... }
void maintain(int o, int l, int r) { ... }
void update_add(int o, int l, int r, int L, int R, ll v) { ... }
void update_set(int o, int l, int r, int L, int R, ll v) { ... }
void query(int o, int l, int r, int L, int R, ll add_acc, Res& res) { ... }
public:
SegTree(int _n) : n(_n) { t.resize(4*n); build(1,1,n); }
void add(int l, int r, ll v) { update_add(1,1,n,l,r,v); }
void set(int l, int r, ll v) { update_set(1,1,n,l,r,v); }
Res ask(int l, int r) { Res res; query(1,1,n,l,r,0,res); return res; }
};
while (scanf("%d%d%d", &R, &C, &M) == 3) {
SegTree st(R * C);
for (int q = 0; q < M; ++q) {
int op, x1, y1, x2, y2; ll v;
scanf("%d%d%d%d%d", &op, &x1, &y1, &x2, &y2);
if (op <= 2) scanf("%lld", &v);
if (op == 1) {
for (int i = x1; i <= x2; ++i) st.add((i-1)*C+y1, (i-1)*C+y2, v);
} else if (op == 2) {
for (int i = x1; i <= x2; ++i) st.set((i-1)*C+y1, (i-1)*C+y2, v);
} else {
ll sum = 0, mn = INF, mx = -INF;
for (int i = x1; i <= x2; ++i) {
Res r = st.ask((i-1)*C+y1, (i-1)*C+y2);
sum += r.sum; mn = min(mn, r.mn); mx = max(mx, r.mx);
}
printf("%lld %lld %lld\n", sum, mn, mx);
}
}
}
N = R*C ≤ 10^6。O(log N)。O(M * R * log N) ≤ 20000 * 20 * 20 ≈ 8×10^6,極快。O(N) 線段樹節點約 4M,可接受。「行數少」是突破口,將二維區間操作轉化為多次一維區間操作。線段樹需正確處理賦值標記優先級高於加法標記的覆蓋語義,PushDown 時先推賦值再推加法。此題是「區間加 + 區間賦值 + 區間查詢」線段樹的經典實戰。