LA-11992-Fast Matrix Operations 快速矩阵操作(线段树成段更新)

来源:互联网 发布:comparebeyond4 mac 编辑:程序博客网 时间:2024/05/17 09:18

题意:

给定一个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 表示输出(x1,y1,x2,y2)(x1<=x2,y1<=y2)子矩阵中的所有元素的sum,最大最小值max,min

线段树基本功能啦。。开r个线段树..(最多20).每次对r个线段树操作就好了

这里有个问题就是,set和add的处理,  要知道set和add不可能同时存在于一个节点中

所以,每次add操作之前都要把当前节点的set标记 推送到 他的儿子中

维护好 sum ,max,min三个信息就可以了

对于查询,写了三个函数,

注意  query_max中 非法区间要返回0,而query_min中非法区间要返回inf 

一开始memset SET数组为-1 表示当前节点无set标记


全程无槽点..1A了...   跑了600ms、留在了VJ第一页、算不错啦。。。上一个线段树代码跑了全VJ倒数第二大哭


#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <algorithm>#include <iostream>#include <queue>#include <map> #include <vector>using namespace std;#define inf 2147483647const int N = 1000050;int  sum[21][2*N], add[21][2*N], SET[21][2*N];int  maxx[21][2*N], minn[21][2*N];int max(int a,int b){return a<b?b:a;}int min(int a,int b){return a>b?b:a;} void pushDown(int i, int l, int r,int num,int op)//把i节点的延迟标记传递到左右儿子节点{if (op==2){if (SET[num][i]!=-1){int mid = (l + r) >> 1;SET[num][i << 1] = SET[num][i];sum[num][i << 1] = (mid - l + 1) * SET[num][i];  //[l, mid]代表左儿子区间SET[num][i << 1 | 1] = SET[num][i];sum[num][i << 1 | 1] = (r - mid) * SET[num][i];  //[mid + 1, r]代表右儿子区间minn[num][i<<1]=maxx[num][i<<1]=maxx[num][i<<1|1]=minn[num][i<<1|1]=SET[num][i];add[num][i<<1]=add[num][i<<1|1]=0;SET[num][i] = -1;}}elseif (op==1){if(add[num][i] != 0){ int mid = (l + r) >> 1;pushDown(i<<1,l,mid,num,2);pushDown(i<<1|1,mid+1,r,num,2);//把儿子的SET传下去add[num][i << 1 | 1] += add[num][i];add[num][i << 1] += add[num][i];sum[num][i << 1] += (mid - l + 1) * add[num][i];  //[l, mid]代表左儿子区间sum[num][i << 1 | 1] += (r - mid) * add[num][i];  //[mid + 1, r]代表右儿子区间minn[num][i<<1]+=add[num][i];maxx[num][i<<1]+=add[num][i];maxx[num][i<<1|1]+=add[num][i];minn[num][i<<1|1]+=add[num][i];add[num][i] = 0;}}}void update(int i, int l, int r, int ql, int qr, int val,int num,int op) //更新区间为qlqr,当前区间为l,r,代表当前区间和的节点为i,更新值为val,op为1是add,2是SET{    if(l > qr || ql > r)//更新区间不在当前区间内        return ;    if(l >= ql && r <= qr)//要更新的区间把当前区间完全包括,则把当前整个区间+val,然后返回上一层{if (op==1)  //add{if (SET[num][i]!=-1)pushDown(i,l,r,num,2);//add之前先把SET传下去 sum[num][i] += (r - l + 1) * val;maxx[num][i]+=val;minn[num][i]+=val;add[num][i]+=val;        }elseif (op==2)//SET{add[num][i]=0;sum[num][i]= (r - l + 1) * val;maxx[num][i]=val;minn[num][i]=val;SET[num][i]=val;}return ;    }//如果上面没reutrn 表示要往左右儿子区间update,所以把延迟标记放下去pushDown(i,l,r,num,2);//先传SETpushDown(i, l, r,num,1);//再传add    int mid = (l + r) >> 1;    update(i << 1, l, mid, ql, qr, val,num,op);    update(i << 1 | 1, mid + 1, r, ql, qr, val,num,op);    sum[num][i] = sum[num][i << 1] + sum[num][i << 1 | 1];maxx[num][i] = max(maxx[num][i << 1] , maxx[num][i << 1 | 1]);minn[num][i] = min(minn[num][i << 1] , minn[num][i << 1 | 1]);}int query(int i, int l, int r, int ql, int qr,int num) //查询区间为qlqr,当前区间为l,r,代表当前区间和的节点为i {    if(l > qr || ql > r)        return 0;    if(l >= ql && r <= qr)        return sum[num][i];pushDown(i,l,r,num,2);//先传SETpushDown(i, l, r,num,1);//再传add    int mid =( l + r) >> 1;    return query(i << 1, l, mid, ql, qr,num)   + query(i << 1 | 1, mid + 1, r, ql, qr,num);}int query_max(int i, int l, int r, int ql, int qr,int num) //查询区间为qlqr,当前区间为l,r,代表当前区间和的节点为i {    if(l > qr || ql > r)        return 0;    if(l >= ql && r <= qr)        return maxx[num][i];pushDown(i,l,r,num,2);//先传SETpushDown(i, l, r,num,1);//再传add    int mid =( l + r) >> 1;    return max(query_max(i << 1, l, mid, ql, qr,num)   , query_max(i << 1 | 1, mid + 1, r, ql, qr,num));}int query_min(int i, int l, int r, int ql, int qr,int num) //查询区间为qlqr,当前区间为l,r,代表当前区间和的节点为i {    if(l > qr || ql > r)        return inf;    if(l >= ql && r <= qr)        return minn[num][i];pushDown(i,l,r,num,2);//先传SETpushDown(i, l, r,num,1);//再传add    int mid =(  l + r) >> 1; return min(query_min(i << 1, l, mid, ql, qr,num)   , query_min(i << 1 | 1, mid + 1, r, ql, qr,num));}int main(){int op;    int r,c,m,i,j;int x1,x2,y1,y2,v;while(    scanf("%d%d%d", &r,&c,&m)!=EOF){memset(sum,0,sizeof(sum));memset(add,0,sizeof(add));memset(maxx,0,sizeof(maxx));memset(minn,0,sizeof(minn));memset(SET,-1,sizeof (SET));for(  i = 1; i <= m; i++){scanf("%d",&op); if (op==1){scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&v);for (j=x1;j<=x2;j++){update(1,1,c,y1,y2,v,j,1);}}elseif (op==2){scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&v); for (j=x1;j<=x2;j++){update(1,1,c,y1,y2,v,j,2);}}else{scanf("%d%d%d%d",&x1,&y1,&x2,&y2); int ans1=0;int ans2=0;int ans3=inf;for (j=x1;j<=x2;j++){ans1+=query(1,1,c,y1,y2,j); ans2=max(ans2,query_max(1,1,c,y1,y2,j));ans3=min(ans3,query_min(1,1,c,y1,y2,j)); }printf("%d %d %d\n",ans1,ans3,ans2);}}}return 0;}




0 0
原创粉丝点击