zoukankan      html  css  js  c++  java
  • 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
    ",sum,mi,mx);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    [转+]C语言复杂声明
    c和c++数组初始化一点小区别
    [转]Linux ftp命令的使用方法
    Ubuntu 12.04 英文版中文输入法设置
    [转]Android手机中获取手机号码和运营商信息
    把google地圖放在Crm Entity中
    为什么报表里面记录的创建时间 比我们电脑客户端的世界时间 隔8个小时?这个是什么原因?
    print style Iframe
    取出MSCRM父窗口的欄位的值
    Display Fetch in IFRAME – Part 2
  • 原文地址:https://www.cnblogs.com/Rye-Catcher/p/8971634.html
Copyright © 2011-2022 走看看