• 题解 UVA11992 【Fast Matrix Operations】


    题目描述

    有一个r行c列的全0矩阵,有以下三种操作。

    • 1 X1 Y1 X2 Y2 v 子矩阵(X1,Y1,X2,Y2)的元素加v

    • 2 X1 Y1 X2 Y2 v 子矩阵(X1,Y1,X2,Y2)的元素变为v

    • 3 X1 Y1 X2 Y2 查询子矩阵(X1,Y1,X2,Y2)的和,最大值,最小值

    子矩阵(X1,Y1,X2,Y2)满足X1<=X<=X2 Y1<=Y<=Y2的所有元素(X1,Y2)。

    输入保证和不超过10^9

    追加翻译:

    数据范围:r <= 20!

    主要思路:线段树 + 暴力枚举 + 懒人代码

    我在追加翻译中强调了,r <= 20,也就是说,我们可以通过维护20棵线段树来维护矩阵的信息。也就是说,我们的中心任务放在了写一棵区间加,区间修改,维护区间和,区间最大值,最小值的一棵线段树。

    …………

    代码冗长……但是如何让自己的线段树更短更好写嘞?

    首先,在下放标记时,我会调用这样的两个函数:

    inline void color_add(int l, int r, int rt, int v) {
        z[rt].maxx += v; 
        z[rt].minn += v;
        z[rt].sum += (r - l + 1) * v;
        z[rt].col += v;
    } 
    inline void color_chg(int l, int r, int rt, int v) {
        z[rt].maxx = z[rt].minn = v;
        z[rt].sum = (r - l + 1) * v;
        z[rt].coll = v;
        z[rt].col = 0;
    }
    

    这两个函数分别是用来修改被下放的子节点的信息的。我们这样可以在下放标记时直接调用,甚至可以用来在修改操作时调用,节省大片代码。

    然后对于询问操作,我们完全可以直接询问一组数据(一组数据就是一个区间的sum, max, min),我们用结构体实现。对于线段树左右节点的信息合并与询问时的信息合并,我们可以直接通过编写函数来简化代码。(细节就在下文代码里看吧)

    我的代码是本题题解截止2019/02/22最短的代码(无注释无过度压行)。

    code

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    #define go(i, j, n, k) for(int i = j; i <= n; i += k)
    #define mn 200100
    #define inf 1 << 30
    #define root 1, n, 1
    #define lson l, m, rt << 1
    #define rson m + 1, r, rt << 1 | 1
    #define bson l, r, rt
    inline int read(){
    	int x = 0, f = 1; char ch = getchar();
    	while(ch > '9' || ch < '0') { if(ch == '-') f = -f; ch = getchar(); }
    	while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    	return x * f;
    }
    struct tree{
    	int col, coll, minn, maxx, sum;
    	tree(int _col = 0, int _coll = -1, int _minn = 0, int _maxx = 0, int _sum = 0) 	
    		: col(_col), coll(_coll), minn(_minn), maxx(_maxx), sum(_sum) {}
    };
    // col -> 区间加的懒标记,coll -> 区间修改的懒标记
    // 这里要注意,如果在另一个结构体中调用这个结构体,那么这个结构体最好要初始化一下,否则可能会出现问题。
    // 我们用结构体的形式封装线段树,我们可以通过定义SegmentTree类型实现多棵线段树的实现
    struct SegmentTree{
    	tree z[mn << 2];
        // 使用外部的结构体类型
    	inline tree op(tree a, tree b) {
    		tree res;
    		res.maxx = max(a.maxx, b.maxx);
    		res.minn = min(a.minn, b.minn);
    		res.sum = a.sum + b.sum;
    		return res;
    	}
        // 这里就是合并信息的懒人函数
    	inline void update(int rt) {
    		z[rt] = op(z[rt << 1], z[rt << 1 | 1]);
    	}
    	inline void color_add(int l, int r, int rt, int v) {
    		z[rt].maxx += v;
    		z[rt].minn += v;
    		z[rt].sum += (r - l + 1) * v;
    		z[rt].col += v;
    	}
    	inline void color_chg(int l, int r, int rt, int v) {
    		z[rt].maxx = z[rt].minn = v;
    		z[rt].sum = (r - l + 1) * v;
    		z[rt].coll = v;
    		z[rt].col = 0;
    	}
    	inline void push_col(int l, int r, int rt) {
    		if(z[rt].coll != -1) { // 要注意初始时不能是0
    			int m = (l + r) >> 1;
    			color_chg(lson, z[rt].coll);
    			color_chg(rson, z[rt].coll);
    			z[rt].coll = -1;
    		}
    		if(z[rt].col) {
    			int m = (l + r) >> 1;
    			color_add(lson, z[rt].col);
    			color_add(rson, z[rt].col);
    			z[rt].col = 0;
    		}
    	}
    	inline void modify(int l, int r, int rt, int nowl, int nowr, int v, int ver) {
    		if(nowl <= l && r <= nowr) {
    			if(ver == 1) color_add(bson, v);
    			else if(ver == 2) color_chg(bson, v);
    			return;
    		}
    		int m = (l + r) >> 1; push_col(bson);
    		if(nowl <= m) modify(lson, nowl, nowr, v, ver);
    		if(m < nowr)  modify(rson, nowl, nowr, v, ver);
    		update(rt);
    	}
    	inline tree query(int l, int r, int rt, int nowl, int nowr) {
    		if(nowl <= l && r <= nowr) return z[rt];
    		int m = (l + r) >> 1; push_col(bson);
    		if(nowl <= m) {
    			if(m < nowr) return op(query(lson, nowl, nowr), query(rson, nowl, nowr));
    			else return query(lson, nowl, nowr);
    		} else return query(rson, nowl, nowr);
    	}
    	inline void build(int l, int r, int rt) {
    		z[rt].col = 0, z[rt].coll = -1;
    		if(l == r) {
    			z[rt].minn = z[rt].maxx = z[rt].sum = 0;
    			return ;
    		}
    		int m = (l + r) >> 1;
    		build(lson), build(rson), update(rt);
    	}
        // 这里建树代码其实是用来初始化的(多组数据嘛)
    } tr[21];
    int n, nn, m;
    
    inline void solve() {
    	go(i, 1, nn, 1) // 每行都要建树
    		tr[i].build(root);
    	go(i, 1, m, 1) {
    		int s = read(), x = read(), y = read(), xx = read(), yy = read(), v;
    		if(s == 1) {
    			v = read();
    			go(j, x, xx, 1) // 对每行的操作
    				tr[j].modify(root, y, yy, v, 1);
    		} else if(s == 2) {
    			v = read();
    			go(j, x, xx, 1) // 对每行的操作
    				tr[j].modify(root, y, yy, v, 2); 
    		} else {
    			int maxx = 0, minn = inf, sum = 0;
    			go(j, x, xx, 1) { // 对每行的操作
    				tree res = tr[j].query(root, y, yy);
    				maxx = max(maxx, res.maxx);
    				minn = min(minn, res.minn);
    				sum += res.sum;
    			}
    			printf("%d %d %d
    ", sum, minn, maxx);
    		}
    	}
    }
    int main(){
    	while(cin >> nn >> n >> m) {
    		solve();
    	}
    	return 0;
    }
    

    希望可以帮助到想简化代码的同学

  • 相关阅读:
    English Training Material
    SingleThreadModel is deprecated in Servlet API version 2.4
    What is the difference Apache (Http Server) and Tomcat (Servlet Container)
    Add a stylesheet link programmatically in ASP.NET
    Detail in Response.redirect and Server.transfer in ASP.NET
    @font-face usage
    实习面试总结(只写了昨天腾讯的面试和拿到offer的一个小公司, 有空再把前面的补上吧)
    redis-cli启动问题
    关于结构体内存对齐
    memcpy 和 memmove
  • 原文地址:https://www.cnblogs.com/yizimi/p/10582027.html
Copyright © 2020-2023  润新知