uva 11992 快速矩阵操作

// UVa11992 Fast Matrix Operations(更易读、更具一般性的版本)
// Rujia Liu
// 注意:所有叶子上总是保留set标记而不会被清除(pushdown只能针对非叶结点),因此maintain函数对于叶子来说并不会重复累加addv[o]
// 本程序在query的时候进行了标记传递(即pushdown),更具一般性,代码可读性也更强,但执行效率较低
// 有兴趣的读者请参考代码仓库中的uva11992.cpp,那个写法是书上例题中的代码,避开了query中的标记传递,执行效率比本代码高


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


const int maxnode = 1<<17;
const int INF = 1000000000;


int op, x1, x2, y1, y2, x, v;


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


  // 维护信息
  void maintain(int o, int L, int R) {//maintain(rc, M+1, R); 
    int lc = o*2, rc = o*2+1;
    if(R > L) {
      sumv[o] = sumv[lc] + sumv[rc];
      minv[o] = min(minv[lc], minv[rc]);
      maxv[o] = max(maxv[lc], maxv[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];
      addv[rc] += addv[o];
      addv[o] = 0; // 清除本结点标记
    }
  }


  void update(int o, int L, int R) {  //for(x = x1; x <= x2; x++) tree[x].update(1, 1, c);
    int lc = o*2, rc = o*2+1;
    if(y1 <= L && y2 >= R) { // 标记修改      
      if(op == 1) addv[o] += v;
      else { setv[o] = v; addv[o] = 0; }
    } 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);
  }


  void query(int o, int L, int R, int& ssum, int& smin, int &smax) {//tree[x].query(1, 1, c, ssum, smin, smax); 
    int lc = o*2, rc = o*2+1;
    maintain(o, L, R); // 处理被pushdown下来的标记
    if(y1 <= L && y2 >= R) {//递归边界,这里已经是一个完整区间,直接可以找到答案更新 
      ssum = sumv[o];
      smin = minv[o];
      smax = maxv[o];
    } else {
      pushdown(o);
      int M = L + (R-L)/2;
      int lsum = 0, lmin = INF, lmax = -INF;
      int rsum = 0, rmin = INF, rmax = -INF;
      if(y1 <= M) query(lc, L, M, lsum, lmin, lmax); else maintain(lc, L, M);
      if(y2 > M) query(rc, M+1, R, rsum, rmin, rmax); else maintain(rc, M+1, R);
      ssum = lsum + rsum;
      smin = min(lmin, rmin);
      smax = max(lmax, rmax);
    }
  }
};


const int maxr = 20 + 5;


IntervalTree tree[maxr];


int main() {
  int r, c, m;
  while(scanf("%d%d%d", &r, &c, &m) == 3) {
    memset(tree, 0, sizeof(tree));
    for(x = 1; x <= r; x++) {
      memset(tree[x].setv, -1, sizeof(tree[x].setv));//为递归查询时,是否存在set作准备 
      tree[x].setv[1] = 0; //起初状态下整个区间为0; 
    }
    while(m--) {
      scanf("%d%d%d%d%d", &op, &x1, &y1, &x2, &y2);
      if(op < 3) {
        scanf("%d", &v);
        for(x = x1; x <= x2; x++) tree[x].update(1, 1, c);
      } else {
        int gsum = 0, gmin = INF, gmax = -INF;
        for(x = x1; x <= x2; x++) {
          int ssum, smin, smax;
          tree[x].query(1, 1, c, ssum, smin, smax);
          gsum += ssum; gmin = min(gmin, smin); gmax = max(gmax, smax);
        }
        printf("%d %d %d\n", gsum, gmin, gmax);
      }
    }
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值