UVaOJ-11992-Fast Matrix Operations 解题报告

       这是一道貌似二维的线段树题,其实会发现二维不能做,要转换为一维。题意:有一个r行c列的矩阵里面有最多不超过10^6个元素,每个元素的位置(x,y)且1<=x<=r,1<=y<=c。最初所有元素都为0,你有三种操作:

1,将子矩阵(x1,y1,x2,y2)中所有的元素都增加v;

2,将子矩阵(x1,y1,x2,y2)中所有元素都设置为v;

3,输出子矩阵(x1,y1,x2,y2)中所有元素的和以及最小元素和最大元素的值。

在Input中的隐含条件:矩阵最多不超过20行,也就是说r<=20。


       我的解题思路:本来想开个二维的线段树,第一维长度是20,第二维长度是10^6 × 4。结果发现内存开不下了……没办法只能转换成一维了,其实一维还好一些。转换成一维以后,由于有两种延迟标记set和add,所以这里面的问题也需要仔细探讨。由于set操作不受前面的操作的影响(也就是说一个矩阵无论之前有多少次不同种类的操作,在set操作之后也只是相当于只做了该次set操作而已),我们假设认为是set操作优先级最高,所以set操作不但要覆盖以前的set操作,还要覆盖add操作(其实就是覆盖所有操作)。而add操作受以前操作的影响,所以直接添加add操作就好。到时候更新节点时两个延迟操作标记同时存在,先做set操作,再做add操作就可以了。


       我的解题代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <cctype>
#include <ctime>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <list>
#include <map>

using namespace std;

#define N 1000000

struct tree     //定义线段树结构体
{
    int left, right, mid;
    int set, add;       //两个延迟标记
    int minvalue, maxvalue, sumvalue;
    void init()
    {
        mid = (left + right) >> 1;
        add = minvalue = maxvalue = sumvalue = 0;
        set = INT_MAX;
        return;
    }
};

tree node[N<<2];
int r, c, m;
int sumans, maxans, minans;

void BuildTree(int left, int right, int x);     //建立线段树

void Query(int left, int right, int x);         //3操作

void Set(int left, int right, int v, int x);    //2操作

void Add(int left, int right, int v, int x);    //1操作

void PushUp(int x);                             //向上更新

void PushDown(int x);                           //向下更新

int main()
{
    int que, x1, x2, y1, y2, v;
    while (~scanf("%d %d %d", &r, &c, &m))
    {
        BuildTree(1, r * c, 1);
        while (m--)
        {
            scanf("%d %d %d %d %d", &que, &x1, &y1, &x2, &y2);
            if (x1 > x2) swap(x1, x2);
            if (y1 > y2) swap(y1, y2);
            if (que == 3)
            {
                //先初始化要输出的答案
                sumans = 0;    
                maxans = -INT_MAX;
                minans = INT_MAX;
                //分段询问并存储答案
                for (int i=x1; i<=x2; ++i) Query((i - 1) * c + y1, (i - 1) * c + y2, 1);                    
                printf("%d %d %d\n", sumans, minans, maxans);
                continue;
            }
            scanf("%d", &v);
            if (que == 2)
            {
                for (int i=x1; i<=x2; ++i) Set((i - 1) * c + y1, (i - 1) * c + y2, v, 1);
            }
            else
            {
                for (int i=x1; i<=x2; ++i) Add((i - 1) * c + y1, (i - 1) * c + y2, v, 1);
            }
        }
    }
    return 0;
}

void BuildTree(int left, int right, int x)
{
    node[x].left = left;
    node[x].right = right;
    node[x].init();
    if (left == right) return;
    BuildTree(left, node[x].mid, x << 1);
    BuildTree(node[x].mid + 1, right, x << 1 | 1);
    return;
}

void Query(int left, int right, int x)
{
    if (node[x].left == left && node[x].right == right)
    {
        sumans += node[x].sumvalue;
        maxans = max(maxans, node[x].maxvalue);
        minans = min(minans, node[x].minvalue);
        return;
    }
    if (node[x].set != INT_MAX || node[x].add != 0) PushDown(x);
    if (right <= node[x].mid)
    {
        Query(left, right, x << 1);
    }
    else if (left > node[x].mid)
    {
        Query(left, right, x << 1 | 1);
    }
    else
    {
        Query(left, node[x].mid, x << 1);
        Query(node[x].mid + 1, right, x << 1 | 1);
    }
    return;
}

void Set(int left, int right, int v, int x)
{
    if (node[x].left == left && node[x].right == right)
    {
        node[x].maxvalue = node[x].minvalue = v;
        node[x].sumvalue = (right - left + 1) * v;
        node[x].set = v;
        node[x].add = 0;    //set操作优先级高,add操作也要被覆盖
        PushUp(x);
        return;
    }
    if (node[x].add != 0 || node[x].set != INT_MAX) PushDown(x);
    if (right <= node[x].mid)
    {
        Set(left, right, v, x << 1);
    }
    else if (left > node[x].mid)
    {
        Set(left, right, v, x << 1 | 1);
    }
    else
    {
        Set(left, node[x].mid, v, x << 1);
        Set(node[x].mid + 1, right, v, x << 1 | 1);
    }
    return;
}

void Add(int left, int right, int v, int x)
{
    if (node[x].left == left && node[x].right == right)
    {
        node[x].maxvalue += v;
        node[x].minvalue += v;
        node[x].sumvalue += v * (right - left + 1);
        node[x].add += v;
        PushUp(x);
        return;
    }
    if (node[x].add != 0 || node[x].set != INT_MAX) PushDown(x);
    if (right <= node[x].mid)
    {
        Add(left, right, v, x << 1);
    }
    else if (left > node[x].mid)
    {
        Add(left, right, v, x << 1 | 1);
    }
    else
    {
        Add(left, node[x].mid, v, x << 1);
        Add(node[x].mid + 1, right, v, x << 1 | 1);
    }
    return;
}

void PushUp(int x)
{
    while (x != 1)
    {
        x >>= 1;
        node[x].sumvalue = node[x<<1].sumvalue + node[x<<1|1].sumvalue;
        node[x].maxvalue = max(node[x<<1].maxvalue, node[x<<1|1].maxvalue);
        node[x].minvalue = min(node[x<<1].minvalue, node[x<<1|1].minvalue);
    }
    return;
}

void PushDown(int x)
{
    if (node[x].left == node[x].right) 
    {
        node[x].add = 0;
        node[x].set = INT_MAX;
        return;
    }
    if (node[x].set != INT_MAX)     //先进行set操作
    { 
        node[x<<1].set = node[x<<1|1].set = node[x].set;
        node[x<<1].add = node[x<<1|1].add = 0;
        node[x<<1].sumvalue = (node[x<<1].right - node[x<<1].left + 1) * node[x].set;
        node[x<<1|1].sumvalue = (node[x<<1|1].right - node[x<<1|1].left + 1) * node[x].set;
        node[x<<1].minvalue = node[x<<1].maxvalue = node[x].set;
        node[x<<1|1].minvalue = node[x<<1|1].maxvalue = node[x].set;
        node[x].set = INT_MAX;
    }
    if (node[x].add != 0)
    {
        node[x<<1].add += node[x].add;
        node[x<<1|1].add += node[x].add;
        node[x<<1].sumvalue += node[x].add * (node[x<<1].right - node[x<<1].left + 1);
        node[x<<1|1].sumvalue += node[x].add * (node[x<<1|1].right - node[x<<1|1].left + 1);
        node[x<<1].maxvalue += node[x].add;
        node[x<<1|1].maxvalue += node[x].add;
        node[x<<1].minvalue += node[x].add;
        node[x<<1|1].minvalue += node[x].add;
        node[x].add = 0;
    }
    return;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值