luogu题解 UVA11992 【Fast Matrix Operations】

  • 题目链接:

https://www.luogu.org/problemnew/show/UVA11992

  • 题目大意:

一个r*c的矩阵,一开始元素都是0,然后给你m次三种操作,分别是将一个子矩阵中所有元素加上v,将一个子矩阵元素全部修改成v,询问一个子矩阵中所有元素和,最大值和最小值.

  • 思路:

应该说是一道有点毒瘤的数据结构题(然而时限居然给了5s)了,虽然它的主体只是线段树。我们可以把每一行都看作一棵线段树,这样操作就十分方便了。

然后就是修改值的操作,对于初学者可能有点棘手,但实际上并不难,我们同样可以用lazy_tag打标记。但是就有一些要注意的东西了,当我们打add(元素加值)标记时是不会影响set(修改值)标记的,但是我们在打set标记时无论你前面add标记是多少,此时就相当于作废,所以直接将add标记赋为0就好了,然后直接修改sum,mi和mx(分别记录该区间的和,最小值,最大值)。

同时我们可以让query询问函数直接返回一个存了sum,mi,mx的结构体,这样就不用查三次了.

同时还有一个去要注意的地方,正如我们前面分析的那样,每一行开一颗线段树,但是实际上你真的不能搞一个tree[maxn],然后每一个tree中存一个线段树的结构体,这样是绝壁会爆的(我一开始就这么搞),而是和平常一样搞一个存全部元素的数组,具体怎么做还请看代码,我自认为还是写的比较直观。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <vector>
using namespace std;
const int maxn=1000005;
const int inf=0xfffffff;
int r,c,m,v;
int L,R;
struct Tmp{
    Tmp() : sum(0), mx(-inf),mi(inf) {}//构造函数,非常方便,强烈推荐
    Tmp(int x,int y,int z) :sum(x),mx(y),mi(z) {}
    int sum;
    int mx,mi;
};//query询问时直接返回这个结构体就好了
int sum[maxn<<2],add[maxn<<2],set[maxn<<2],mx[maxn<<2],mi[maxn<<2];
inline void up(int now){
    sum[now]=sum[now<<1]+sum[now<<1|1];
    mx[now]=max(mx[now<<1],mx[now<<1|1]);
    mi[now]=min(mi[now<<1],mi[now<<1|1]);
    return ;
}
void build(int now,int l,int r){//其实build一点用也没有,请大家忽略
    if(l==r){
        mx[now]=0;//-inf;
        mi[now]=0;//inf;
        return ;
    }
    int mid=(l+r)>>1;
    build(now<<1,l,mid);
    build(now<<1|1,mid+1,r);
    up(now);
    return ;
}
inline void down(int now,int ln,int rn){//注意看这个push_down函数
        if(set[now]){//修改标记
            sum[now<<1]=set[now]*ln;
            sum[now<<1|1]=set[now]*rn;
            set[now<<1]=set[now];
            set[now<<1|1]=set[now];
            add[now<<1]=add[now<<1|1]=0;
            mx[now<<1]=mx[now<<1|1]=set[now];
            mi[now<<1]=mi[now<<1|1]=set[now];
            set[now]=0;
        }
        if(add[now]){//加值标记
            sum[now<<1]+=add[now]*ln;
            sum[now<<1|1]+=add[now]*rn;
            add[now<<1]+=add[now];
            add[now<<1|1]+=add[now];
            mx[now<<1]+=add[now];
            mi[now<<1]+=add[now];
            mx[now<<1|1]+=add[now];
            mi[now<<1|1]+=add[now];
            add[now]=0;
        }
        return ;
}
void update_add(int now,int l,int r){
        if(L<=l&&r<=R){
            add[now]+=v;
            sum[now]+=v*(r-l+1);
            mx[now]+=v;
            mi[now]+=v;
            return ;
        }
        int mid=(l+r)>>1;
        down(now,mid-l+1,r-mid);
        if(L<=mid)update_add(now<<1,l,mid);
        if(mid<R)update_add(now<<1|1,mid+1,r);
        up(now);
        return ;
}
void update_set(int now,int l,int r){
        if(L<=l&&r<=R){
            set[now]=v;
            sum[now]=v*(r-l+1);
            add[now]=0;
            mx[now]=v;
            mi[now]=v;
            return ;
        }
        int mid=(l+r)>>1;
        down(now,mid-l+1,r-mid);
        if(L<=mid)update_set(now<<1,l,mid);
        if(mid<R)update_set(now<<1|1,mid+1,r);
        up(now);
        return ;
}
Tmp query(int now,int l,int r){
        if(L<=l&&r<=R){
            return Tmp(sum[now],mx[now],mi[now]);//十分方便
        }
        int mid=(l+r)>>1;
        down(now,mid-l+1,r-mid);
        Tmp tmp;
        int sum=0,mx=-inf,mi=inf;
        if(L<=mid){
            tmp=query(now<<1,l,mid);
            sum+=tmp.sum;
            mx=max(mx,tmp.mx);
            mi=min(mi,tmp.mi);
        }
        if(mid<R){
            tmp=query(now<<1|1,mid+1,r);
            sum+=tmp.sum;
            mx=max(mx,tmp.mx);
            mi=min(mi,tmp.mi);
        }
      //  up(now);        //然而并不用up()
        tmp.sum=sum,tmp.mi=mi,tmp.mx=mx;
        return tmp;
}
template <class T>inline void read(T &x){
    x=0;int ne=0;char c;
    while(!isdigit(c=getchar()))ne=c==‘-‘;
    x=c-48;
    while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
    x=ne?-x:x;
    return ;
}
int main()
{
    int op,x1,x2,y1,y2;
    read(r),read(c),read(m);
   // build(1,1,r*c);
    while(m--){
        read(op),read(x1),read(y1),read(x2),read(y2);
        if(op==1){
            read(v);
            for(register int i=x1;i<=x2;i++){
                L=(i-1)*c+y1,R=(i-1)*c+y2;   //注意处理技巧!!!
                update_add(1,1,r*c);  //r*c是所有元素的范围
            }
        }
        else if(op==2){
            read(v);
            for(register int i=x1;i<=x2;i++){
                L=(i-1)*c+y1,R=(i-1)*c+y2;   //注意处理技巧!!!
                update_set(1,1,r*c);
            }
        }
        else {
            Tmp tmp;
            int sum=0,mx=-inf,mi=inf;
            for(register int i=x1;i<=x2;i++){
                L=(i-1)*c+y1,R=(i-1)*c+y2;   //注意处理技巧!!!
                tmp=query(1,1,r*c);
                sum+=tmp.sum;
                mx=max(mx,tmp.mx);
                mi=min(mi,tmp.mi);
            }
            printf("%d %d %d\n",sum,mi,mx);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Rye-Catcher/p/8971634.html

时间: 2024-10-09 19:58:42

luogu题解 UVA11992 【Fast Matrix Operations】的相关文章

UVA11992 - Fast Matrix Operations(段树部分的变化)

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行,所以能够将这个矩阵的元素构建一

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

[uva11992]Fast Matrix Operations(多延迟标记,二维线段树,区间更新)

题目链接:https://vjudge.net/problem/UVA-11992 题意:n*m的矩阵,每次对一个子矩阵操作,有三种操作:加x,设置为x,查询.查询返回子矩阵和.最小值.最大值 n很小(<=20),所以可以开20棵线段树,每次操作按行更新. 特别小心put和add两个延迟标记,坑老惨了. put初始化-1最简单的坑,略过. build的时候要每一个节点都要clear,不能只clear叶子.因为会有直接差没操作的子矩阵(因为初始化都是0). 数组开大... add的话,什么都不用管

uva11992 Fast Matrix Operations

题意:r*c的矩阵上,初始全部为0,有3中操作,子矩阵全部增加v,子矩阵值修改为v,查询子矩阵的最大值,最小值,和 分析:因为有setv和addv两种操作,那么需要开两个数组记录这个值,每次需要用到一个节点的儿子,那么就把该节点的setv,addv信息推过去,并且setv的优先级要高于addv,不过这样的后果就是,慢 不过这样写思维难度和编程难度降低了,一般并不会发生线段树不够快的情况 1 #include<iostream> 2 #include<cstring> 3 #incl

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.然后修改查询

UVA11992:Fast Matrix Operations(线段树)

题意: 有一个初始状态全为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 v:查询子矩阵(x1,y1,x2,y2)的元素和,最大值和最小值 思路: 因为总元素葛素不超过10^6,而且更新是对于连续的行进行更新,所以我们可以把矩阵转化为一个一元组,通过下一行拼接在上一行的末尾,那么在更新与查询的时候只要对相应的区间进行操作即可 #in

Fast Matrix Operations

uva11992:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3143 题意:给你n*m的矩阵初始化的时候矩阵里面的元素全部是0,对于这个矩阵有3中操作. 1 x1 y1 x2 y2 v   把(x1 y1 x2 y2)子矩阵 里面的元素全部加上v 2 x1 y1 x2 y2 v   把(x1 y1 x2 y2)子矩阵 里面的元素全部置成

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

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

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 表示输