LA-11992-Fast Matrix Operations 快速矩阵操作(线段树成段更新)
2015-09-06 18:19
399 查看
题意:
给定一个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倒数第二
给定一个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 2147483647 const 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; } } else if (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; } else if (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); //先传SET pushDown(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); //先传SET pushDown(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); //先传SET pushDown(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); //先传SET pushDown(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); } } else if (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; }
相关文章推荐
- 编写shell脚本自动跳到某个目录
- Nginx优化指南+LINUX内核优化+linux连接数优化+nginx连接数优化
- SELL学习笔记前言:我对SHELL学习的计划
- 安装xampp后apache不能启动解决方法
- 【转】LINUX下一款不错的网站压力测试工具webbench
- Windows API 之 OpenProcessToken、GetTokenInformation
- 从一道面试题谈linux下fork的运行机制
- Linux下的split 命令(将一个大文件根据行数平均分成若干个小文件)
- Linux下VIM编辑器的详细使用
- runloop总结
- Hadoop 学习
- InternetOpenA
- 动态网站开发技术
- nginx之基础命令(启动、停止、平滑重启、平滑升级)
- Apache windows安装
- jenkins , ant ctomcat+shell报ant: command not foun.
- 6-8月份工作总结(一)——Kongsberg公司演示EM2040C和TOPAS
- CentOS下安装nginx rpm包
- Linux学习之Shell编程基础
- 如何利用General框架进行三层架构开发