uva 1401 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的所有元素(x,y)。

矩阵不超过20行,矩阵总元素可多达10^6个。

思路:矩阵行数不超过20行,元素总数可达10^6 可以想到每行建一个线段树。

两个操作 add和set ,所以需要两个标记addv和setv。

规定同时有两个标记时 , 表示先执行set再执行add。

在update函数的递归边界上 对于set操作,需要将该节点addv标记清除,但对于add操作,不清除setv标记;

在maintain函数中要先考虑setv,再考虑addv;

在query函数中,需要综合考虑setv和addv的影响;

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int r,c,m;
int op,x1,y1,x2,y2,v,x;
int _sum, _min, _max;

const int maxnode = 1<<17;

struct IntervalTree{
    int addv[maxnode],setv[maxnode],sumv[maxnode],minv[maxnode],maxv[maxnode];

    void maintain(int o, int L, int R){
        int lc = o*2, rc = o*2+1;
        if(L < R){
            sumv[o] = sumv[lc] + sumv[rc];
            maxv[o] = max(maxv[lc], maxv[rc]);
            minv[o] = min(minv[lc], minv[rc]);
        }
        if(setv[o] >= 0){
            minv[o] = maxv[o] = setv[o];
            sumv[o] = setv[o] * (R-L+1);
        }
        if(addv[o]){
            minv[o] += addv[o];
            maxv[o] += addv[o];
            sumv[o] += addv[o] * (R-L+1);
        }
    }
    void pushdown(int o){
        int lc = o*2, rc = o*2+1;
        if(setv[o] >= 0){
            setv[lc] = setv[rc] = setv[o];
            addv[lc] = addv[rc] = 0;
            setv[o] = -1;
        }
        if(addv[o]){
            addv[lc] += addv[o]; /// wrong answer
            addv[rc] += addv[o]; /// wrong answer
            addv[o] = 0;
        }
    }
    void update(int o, int L, int R){
        int lc = o*2, rc = o*2+1;
        if(y1 <= L && y2 >= R){
            if(op == 2){
                setv[o] = v;
                addv[o] = 0;
            }
            else{
                addv[o] += v;
            }
        }
        else{
            pushdown(o);
            int M = L + (R-L)/2;
            if(y1 <= M) update(lc, L, M);
            else maintain(lc, L, M);
            if(y2 > M) update(rc, M+1, R);
            else maintain(rc, M+1, R);
        }
        maintain(o, L, R); /// wrong answer;
    }
    void query(int o, int L, int R, int add){
        if(setv[o] >= 0){
            int v = setv[o] + addv[o] + add;
            _sum += v * (min(R, y2)-max(L, y1)+1); /// wrong answer
            _max = max(_max, v);
            _min = min(_min, v);
        }
        else if(y1 <= L && y2 >= R){
            _sum += sumv[o] + add*(R-L+1); /// wrong answer
            _max = max(_max, maxv[o]+add); /// wrong answer
            _min = min(_min, minv[o]+add); /// wrong answer
        }
        else{
            int lc = o*2, rc = o*2+1;
            int M = L + (R-L)/2;
            if(y1 <= M) query(lc, L, M, add+addv[o]);
            if(y2 > M) query(rc, M+1, R, add+addv[o]);
        }
    }
}tree[25];

const int INF = 0x3f3f3f3f;

int main(){
    while(scanf("%d%d%d",&r,&c,&m) != EOF){

        memset(tree, 0, sizeof(tree));
        for(int i = 0; i <= r; i++){
            memset(tree[i].setv, -1, sizeof(tree[i].setv));
            tree[i].setv[1] = 0;/// wrong answer point
        }
        while(m--){
            scanf("%d%d%d%d%d",&op,&x1,&y1,&x2,&y2);
            if(op < 3){
                scanf("%d",&v);
                for(int x = x1; x <= x2; x++){
                    tree[x].update(1, 1, c);
                }
            }
            else{
                _max = -INF;_min = INF;_sum = 0;
                for(int x = x1; x <= x2; x++){
                    tree[x].query(1, 1, c, 0);
                }
                printf("%d %d %d\n",_sum, _min, _max);
            }
        }
    }

    return 0;
}

上面代码中的 wrong answer 处,是在敲线段树时犯错的地方。第一次做线段树的题目,标记出来提醒自己。

main函数中先对线段树数组 tree[]数组 清零~

另外将所有的setv[]点设成-1值,表示该节点并没有 被修改过;

但是!但是不要忘记紧接着写上:tree[i].setv[1] = 0; 这个不可少,因为它的意思是,将本行(线段树中)所有元素的值设为零,即相当于初始化~ 没写这个wrong了两发T_T。。。

时间: 2024-10-29 08:01:35

uva 1401 Fast Matrix Operations 快速矩阵操作 (线段树 区间修改和查询)的相关文章

UVA 11992 - Fast Matrix Operations

Fast Matrix Operations There is a matrix containing at most 106 elements divided into r rows and c columns. Each element has a location (x,y) where 1<=x<=r,1<=y<=c. Initially, all the elements are zero. You need to handle four kinds of operati

UVA11992 - Fast Matrix Operations ( 线段树 + 区间修改 + 好题 )

UVA11992 - Fast Matrix Operations ( 线段树 + 区间修改 + 好题 ) 这是大白书上的例题,一直放着没有去A掉,这是一道线段树区间修改的好题. 线段树中需要维护三个域 ,max, min, sum,也就是区间最大值,最小值,区间和 题目大意: 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

UVa 11992 Fast Matrix Operations (线段树)

Fast Matrix Operations Description There is a matrix containing at most 106 elements divided into r rows and c columns. Each element has a location (x, y) where 1 ≤ x ≤ r, 1 ≤ y ≤ c. Initially, all the elements are zero. You need to handle four kinds

UVa 11992 Fast Matrix Operations(线段树双懒操作,二维转一维)

题意:给个r*c的矩形,三种操作,将一个子矩形权值+v,将一个子矩阵权值赋值为v,查询一个子矩阵sum,max,min.起初矩阵权值为0,保证r<=20,r*c<=1e6,操作次数不超过10000 链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18697 题解:将二维转一维,设当前点为(x,y),则它在线段树上的点为(x-1)*c+y,由于行不超过20行,不妨枚举每一行,去操作.对于一维的线段树,要进行赋值,加法

线段树(多维+双成段更新) UVA 11992 Fast Matrix Operations

题目传送门 题意:训练指南P207 分析:因为矩阵不超过20行,所以可以建20条线段的线段树,支持两个区间更新以及区间查询. #include <bits/stdc++.h> using namespace std; #define lson l, mid, o << 1 #define rson mid + 1, r, o << 1 | 1 typedef long long ll; const int INF = 0x3f3f3f3f; const int N =

UVa 11992 (线段树 区间修改) Fast Matrix Operations

比较综合的一道题目. 二维的线段树,支持区间的add和set操作,然后询问子矩阵的sum,min,max 写完这道题也是醉醉哒,代码仓库里还有一份代码就是在query的过程中也pushdown向下传递标记. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int maxnode = 1 << 17; 7 int _

UVA11992 - Fast Matrix Operations(线段树区间修改)

题目链接 题目大意:给你个r*c的矩阵,初始化为0. 然后给你三种操作: 1 x1, y1, x2, y2, v 把由x1,y1, x2, y2构成的子矩阵里的每个元素都加上v. 2 x1, y1, x2, y2, v 把这个子矩阵的每个元素都修改为v. 3 x1, y1, x2, y2 查询这个子矩阵的元素之和,和这些元素的最大值和最小值. 解题思路:因为矩阵的行最多20行,所以可以将这个矩阵的元素构建一棵线段树,每个节点都有三个附加信息:sum,Max_num, Min_num.然后修改查询

UVA 11992 Fast Matrix Operations (降维)

题意:对一个矩阵进行子矩阵操作. 元素对多有1e6个,树套树不好开(我不会),把二维坐标化成一维的,一个子矩阵操作分解成多条线段的操作. 一次操作的复杂度是RlogC,很容易找到极端的数据(OJ上实测没有),如果判断一下然后建树复杂度是min(RlogC,ClogR). 代码中结点没有保存l和r,而且询问是保存在全局变量中,这样做比较省空间.但是也有缺点,比如推区间结点数量的时候会麻烦一点. #include<bits/stdc++.h> using namespace std; const

Fast Matrix Operations(UVA)11992

UVA 11992 - Fast Matrix Operations 给定一个r*c(r<=20,r*c<=1e6)的矩阵,其元素都是0,现在对其子矩阵进行操作. 1 x1 y1 x2 y2 val 表示将(x1,y1,x2,y2)(x1<=x2,y1<=y2)子矩阵中的所有元素add上val: 2 x1 y1 x2 y2 val 表示将(x1,y1,x2,y2)(x1<=x2,y1<=y2)子矩阵中的所有元素set为val: 3 x1 y1 x2 y2 val 表示输