首页 > 代码库 > UVA 11992 - 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 operations:

1 x1 y1 x2 y2 v

Increment each element (x,y) in submatrix (x1,y1,x2,y2) by v (v>0)

2 x1 y1 x2 y2 v

Set each element (x,y) in submatrix (x1,y1,x2,y2) to v

3 x1 y1 x2 y2

Output the summation, min value and max value of submatrix (x1,y1,x2,y2)

In the above descriptions, submatrix (x1,y1,x2,y2) means all the elements (x,y) satisfying x1<=x<=x2 and y1<=x<=y2. It is guaranteed that 1<=x1<=x2<=r, 1<=y1<=y2<=c. After any operation, the sum of all the elements in the matrix does not exceed 109.

 

Input

There are several test cases. The first line of each case contains three positive integers r, c, m, where m (1<=m<=20,000) is the number of operations. Each of the next m lines contains a query. There will be at most twenty rows in the matrix. The input is terminated by end-of-file (EOF). The size of input file does not exceed 500KB.

Output

For each type-3 query, print the summation, min and max.

Sample Input

4 4 8
1 1 2 4 4 5
3 2 1 4 4
1 1 1 3 4 2
3 1 2 4 4
3 1 1 3 4
2 2 1 4 4 2
3 1 2 4 4
1 1 1 4 3 3

Output for the Sample Input

45 0 5
78 5 7
69 2 7
39 2 7

这两天一直再搞线段树,没写好一道题,加上学业一下子忙起来,没来得及更新博客,今天终于把一道题写好了.此题是线段树的综合应用,题很好,对区间维护要求大.要特别注意区间累加和重置操作的关系,有无影响。

/*
* @author  Panoss
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<ctime>
#include<stack>
#include<queue>
#include<list>
using namespace std;
#define DBG 0
#define fori(i,a,b) for(int i = (a); i < (b); i++)
#define forie(i,a,b) for(int i = (a); i <= (b); i++)
#define ford(i,a,b) for(int i = (a); i > (b); i--)
#define forde(i,a,b) for(int i = (a); i >= (b); i--)
#define forls(i,a,b,n) for(int i = (a); i != (b); i = n[i])
#define mset(a,v) memset(a, v, sizeof(a))
#define mcpy(a,b) memcpy(a, b, sizeof(a))
#define dout  DBG && cerr << __LINE__ << " >>| "
#define checkv(x) dout << #x"=" << (x) << " | "<<endl
#define checka(array,a,b) if(DBG) { \
    dout << #array"[] | " << endl;     forie(i, a, b) cerr << "[" << i << "]=" << array[i] << " |" << ((i - (a)+1) % 5 ? " " : "\n"); if (((b)-(a)+1) % 5) cerr << endl; }
#define redata(T, x) T x; cin >> x
#define MIN_LD -2147483648
#define MAX_LD  2147483647
#define MIN_LLD -9223372036854775808
#define MAX_LLD  9223372036854775807
#define MAX_INF 18446744073709551615
inline int  reint() { int d; scanf("%d", &d); return d; }
inline long relong() { long l; scanf("%ld", &l); return l; }
inline char rechar() { scanf(" "); return getchar(); }
inline double redouble() { double d; scanf("%lf", &d); return d; }
inline string restring() { string s; cin >> s; return s; }

#define MAX_TREE_NODE 50000         ///树结点个数

struct Segment_Tree
{
    int L, R;                       ///左,右区间
    long min_value, max_value;      ///区间最小值,最大值;
    long sum;                       ///区间和
    bool add_flag;                  ///区间是否增个某个数值标志
    long add_value;                 ///区间增量
    bool set_flag;                  ///区间是否重置为某个数值标志
    long set_value;                 ///设置值
    struct Segment_Tree * left;     ///左儿子
    struct Segment_Tree * right;    ///右儿子
};


Segment_Tree Tree[25][2 * MAX_TREE_NODE + 5];

int Tree_node_number = 1;                                   ///结点编号,1号为根结点

int Mid(Segment_Tree * root) { return (root->L + (root->R - root->L) / 2); }

void Build_Tree(Segment_Tree * root, int left, int right,int k)  ///建树,第k棵树
{
    root->L = left;
    root->R = right;
    root->max_value =http://www.mamicode.com/ MIN_LD;
    root->min_value =http://www.mamicode.com/ MAX_LD;
    root->sum = 0;
    root->add_value = http://www.mamicode.com/0;
    root->add_flag = false;
    root->set_value = http://www.mamicode.com/0;
    root->set_flag = false;
    root->left = NULL;
    root->right = NULL;
    if (left == right) return;
    Tree_node_number++;
    root->left = Tree[k] + Tree_node_number;
    Tree_node_number++;
    root->right = Tree[k] + Tree_node_number;
    Build_Tree(root->left, left, (left + right) / 2,k);
    Build_Tree(root->right, (left + right) / 2 + 1, right,k);
}

void updata(Segment_Tree * root)   ///维护根结点的信息
{
    if (root->R > root->L)
    {
        root->max_value = http://www.mamicode.com/max(root->left->max_value, root->right->max_value);
        root->min_value = http://www.mamicode.com/min(root->left->min_value, root->right->min_value);
        root->sum = root->left->sum + root->right->sum;
    }

    if (root->set_flag)
    {
        root->max_value = http://www.mamicode.com/root->set_value;
        root->min_value = http://www.mamicode.com/root->set_value;
        root->sum = root->set_value * (root->R - root->L + 1);
    }

    if (root->add_flag)
    {
        root->max_value += root->add_value;
        root->min_value += root->add_value;
        root->sum += root->add_value * (root->R - root->L + 1);
    }

}

void pushdown(Segment_Tree *root)   ///传递标记
{
    if (root->set_flag)
    {
        root->left->set_value = http://www.mamicode.com/root->set_value;
        root->left->set_flag = true;
        root->left->add_value = http://www.mamicode.com/0;
        root->left->add_flag = false;

        root->right->set_value = http://www.mamicode.com/root->set_value;
        root->right->set_flag = true;
        root->right->add_value = http://www.mamicode.com/0;
        root->right->add_flag = false;

        root->set_flag = false;
        root->set_value = http://www.mamicode.com/0;
    }

    if (root->add_flag)
    {
        root->left->add_value += root->add_value;
        root->left->add_flag = true;

        root->right->add_value += root->add_value;
        root->right->add_flag = true;

        root->add_flag = false;
        root->add_value = http://www.mamicode.com/0;
    }

}


void Add_value(Segment_Tree * root, int i, int j, int value)  ///为区间i,j每个元素加value
{
    if (i <= root->L && root->R <= j)
    {
        root->add_flag = true;
        root->add_value += value;
    }
    else
    {
        pushdown(root);

        if (i <= Mid(root))
        {
            Add_value(root->left, i, j, value);
        }
        else
        {
            updata(root->left);
        }
        if (Mid(root) < j)
        {
            Add_value(root->right, i, j, value);
        }
        else
        {
            updata(root->right);
        }
    }

    updata(root); 
}

void Set_value(Segment_Tree * root, int i, int j, int value)    ///重置区间i,j每个元素为value
{
    if (i <= root->L && root->R <= j)
    {
        root->set_flag = true;
        root->set_value =http://www.mamicode.com/ value;
        root->add_value = http://www.mamicode.com/0;             
        root->add_flag = false;
    }
    else
    {
        pushdown(root);

        if (i <= Mid(root))
        {
            Set_value(root->left, i, j, value);
        }
        else
        {
            updata(root->left);
        }
        if (Mid(root) < j)
        {
            Set_value(root->right, i, j, value);
        }
        else
        {
            updata(root->right);
        }
    }

    updata(root);
}


void Change_node(Segment_Tree * root, int number, int value)   ///修改数据 a[number] = value;
{
    if (root->L == number && root->R == number)   ///叶子结点,直接修改,更新最大值最小值为value,区间和也是value
    {
        root->sum = root->max_value = root->min_value =http://www.mamicode.com/ value;
    }
    else
    {
        if (number <= Mid(root))
        {
            Change_node(root->left, number, value);
        }
        else
        {
            Change_node(root->right, number, value);
        }

        updata(root);
    }
}


long Query_min_value(Segment_Tree * root, int i, int j,int add_total)     ///查询区间i,j最小值
{
    long ans_min = MAX_LD;

    if (root->set_flag)
    {
        long total_value = http://www.mamicode.com/root->set_value + add_total;
        if (root->add_flag) total_value += root->add_value;

        ans_min = min(ans_min, total_value);
    }

    else if (i <= root->L && root->R <= j)
    {
        ans_min = min(ans_min, root->min_value + add_total);
    }
    else
    {
        if (root->add_flag)
        {
            long left_min = MAX_LD, right_min = MAX_LD;
            if (i <= Mid(root))
                left_min = Query_min_value(root->left, i, j, add_total + root->add_value);
            if (j > Mid(root))
                right_min = Query_min_value(root->right, i, j, add_total + root->add_value);
            ans_min = min(left_min, right_min);
        }
        else
        {
            long left_min = MAX_LD, right_min = MAX_LD;
            if (i <= Mid(root))
                left_min = Query_min_value(root->left, i, j, add_total);
            if (j > Mid(root))
                right_min = Query_min_value(root->right, i, j, add_total);
            ans_min = min(left_min, right_min);
        }

    }
    return  ans_min;
}

long Query_max_value(Segment_Tree * root, int i, int j,int add_total)    ///查询区间i,j最大值
{

    long ans_max = MIN_LD;

    if (root->set_flag)
    {
        long total_value = http://www.mamicode.com/root->set_value + add_total;
        if (root->add_flag) total_value += root->add_value;

        ans_max = max(ans_max, total_value);
    }

    else if (i <= root->L && root->R <= j)
    {
        ans_max = max(ans_max, root->max_value + add_total);
    }
    else
    {
        if (root->add_flag)
        {
            long left_max = MIN_LD, right_max = MIN_LD;
            if (i <= Mid(root))
                left_max = Query_max_value(root->left, i, j, add_total + root->add_value);
            if (j > Mid(root))
                right_max = Query_max_value(root->right, i, j, add_total + root->add_value);
            ans_max = max(left_max, right_max);
        }
        else
        {
            long left_max = MIN_LD, right_max = MIN_LD;
            if (i <= Mid(root))
                left_max = Query_max_value(root->left, i, j, add_total);
            if (j > Mid(root))
                right_max = Query_max_value(root->right, i, j, add_total);
            ans_max = max(left_max, right_max);
        }
    }
    return  ans_max;
}

long Get_sum(Segment_Tree *root, int i, int j, int add_total)   ///求区间i,j的和
{
    long ans_sum = 0;

    if (root->set_flag)
    {
        long value_total = root->set_value + add_total;
        if (root->add_flag) value_total += root->add_value;

        ans_sum += value_total * ( min(root->R,j) - max(root->L,i) + 1);


    }

    else if (i <= root->L && root->R <= j)
    {
        ans_sum += root->sum + add_total * (root->R - root->L + 1);
    }
    else
    {
        if (root->add_flag)
        {
            if(i <= Mid(root) )
                ans_sum += Get_sum(root->left, i, j, add_total + root->add_value);
            if(Mid(root) < j)
                ans_sum += Get_sum(root->right, i, j, add_total + root->add_value);
        }
        else
        {
            if (i <= Mid(root))
                ans_sum += Get_sum(root->left, i, j, add_total );
            if (Mid(root) < j)
                ans_sum += Get_sum(root->right, i, j, add_total );
        }
    }
    return ans_sum;
}

int main()
{
    int r, c, m, op;
    int x1, y1, x2, y2, value;
    while (scanf("%d%d%d", &r, &c, &m) == 3)
    {
        mset(Tree,0);

        forie(i, 1, r)    ///为每一行建一棵线段树
        {
            Tree_node_number = 1;
            Build_Tree(Tree[i] + 1, 1, c, i);
        }
        forie(i, 1, r)    ///为每一棵线段树插入每个元素为0
        {
            Set_value(Tree[i] + 1, 1, c, 0);///直接每行全部清0,或者调用Chang_node修改数据
        }

        forie(T, 1, m)
        {
            scanf("%d", &op);
            if (op == 1)
            {
                scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &value);
                forie(i, x1, x2)
                {
                    Add_value(Tree[i] + 1, y1, y2, value);
                }
            }
            if (op == 2)
            {
                scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &value);
                forie(i, x1, x2)
                {
                    Set_value(Tree[i] + 1, y1, y2, value);
                }
            }
            if (op == 3)
            {
                long ans_sum = 0, ans_min = MAX_LD, ans_max = MIN_LD;

                scanf("%d%d%d%d", &x1, &y1, &x2, &y2);

                forie(i, x1, x2)
                {
                    ans_sum += Get_sum(Tree[i] + 1, y1, y2, 0);
                }

                forie(i, x1, x2)
                {
                    ans_min = min(ans_min, Query_min_value(Tree[i] + 1, y1, y2, 0));
                }

                forie(i, x1, x2)
                {
                    ans_max = max(ans_max, Query_max_value(Tree[i] + 1, y1, y2, 0));
                }

                printf("%ld %ld %ld\n", ans_sum, ans_min, ans_max);
            }
        }
    }
    return 0;
}