UVA11992二维线段树区间修改
2015-11-04 23:28
477 查看
#include <iostream> #include <algorithm> #include <stdio.h> #include <string.h> #include <numeric> using namespace std; #define MAXN 100006 #define inf 0x3f3f3f3f struct CNode { int L,R; long long nsum; int nmax; int nmin; long long Inc;//增量n累加nsum + Inc*(R-L+1) int setC;//修改标记位 CNode*pLeft,*pRight; }; CNode Tree[30][3*MAXN]; int nCount[30] ={0}; int Mid(CNode*pRoot) { return (pRoot->L+pRoot->R)/2; } void PushUp(CNode*pRoot) { pRoot->nmin = min(pRoot->pLeft->nmin,pRoot->pRight->nmin); pRoot->nmax = max(pRoot->pLeft->nmax,pRoot->pRight->nmax); pRoot->nsum = pRoot->pLeft->nsum + pRoot->pRight->nsum; } void PushDown(CNode*pRoot) { if (pRoot->setC!=-1) { //set会清除inc pRoot->pLeft->Inc = pRoot->pRight->Inc = 0; pRoot->pRight->setC = pRoot->pLeft->setC = pRoot->setC; pRoot->pRight->nmax = pRoot->pLeft->nmax = pRoot->setC; pRoot->pRight->nmin = pRoot->pLeft->nmin = pRoot->setC; int len1 = pRoot->pLeft->R - pRoot->pLeft->L + 1; int len2 = pRoot->pRight->R - pRoot->pRight->L + 1; pRoot->pLeft->nsum = len1*pRoot->setC; pRoot->pRight->nsum = len2*pRoot->setC; pRoot->setC = -1; } long long tt = pRoot->Inc; if (pRoot->Inc>0) { pRoot->pLeft->Inc+= tt; pRoot->pRight->Inc +=tt; pRoot->pLeft->nmax+=tt;pRoot->pRight->nmax+=tt; pRoot->pLeft->nmin+=tt;pRoot->pRight->nmin+=tt; int len1 = pRoot->pLeft->R - pRoot->pLeft->L + 1; int len2 = pRoot->pRight->R - pRoot->pRight->L + 1; pRoot->pLeft->nsum += len1*pRoot->Inc; pRoot->pRight->nsum += len2*pRoot->Inc; pRoot->Inc = 0; } } //对于第i行的进行建树操作 void BuildTree(int i,CNode*pRoot,int L,int R) { pRoot->L = L; pRoot->R = R; pRoot->nmax = pRoot->nmin = 0; pRoot->nsum = 0; pRoot->Inc = 0; pRoot->setC = -1; if (L!=R) { nCount[i]++; pRoot->pLeft = Tree[i]+nCount[i]; nCount[i]++; pRoot->pRight = Tree[i]+nCount[i]; BuildTree(i,pRoot->pLeft,L,(L+R)/2); BuildTree(i,pRoot->pRight,(L+R)/2+1,R); } } void Add(CNode*pRoot,int a,int b,long long c) { if(pRoot->L==a&&pRoot->R==b) { //懒惰标记 pRoot->Inc+=c; pRoot->nmax += c; pRoot->nmin += c; //重新计算区间的和 pRoot->nsum += (b-a+1)*c; return; } else { //检查当前的懒惰标记 PushDown(pRoot); //分治处理左右子树 int mid = Mid(pRoot); if (b<=mid) { Add(pRoot->pLeft,a,b,c); } else if(a>mid) { Add(pRoot->pRight,a,b,c); } else { Add(pRoot->pLeft,a,mid,c); Add(pRoot->pRight,mid+1,b,c); } PushUp(pRoot); } } //更新区间中的所有值只更新到指定区间[a,b]的与结点重合的时候 //当一次查询到饿时候在往下更新 void Modify(CNode*pRoot,int a,int b,long long c) { if(pRoot->L==a&&pRoot->R==b) { //懒惰标记 pRoot->setC = c; pRoot->Inc = 0; pRoot->nmax = c; pRoot->nmin = c; //重新计算区间的和 pRoot->nsum = (b-a+1)*c; return; } else { //检查当前的懒惰标记 PushDown(pRoot); //分治处理左右子树 int mid = Mid(pRoot); long long ans = 0; if (b<=mid) { Modify(pRoot->pLeft,a,b,c); } else if(a>mid) { Modify(pRoot->pRight,a,b,c); } else { Modify(pRoot->pLeft,a,mid,c); Modify(pRoot->pRight,mid+1,b,c); } PushUp(pRoot); } } int amax[22],amin[22],asum[22]; void Query(int k,CNode*pRoot,int a,int b) { if (pRoot->L==a&&pRoot->R==b) { asum[k]+=pRoot->nsum; amax[k] = max(amax[k],pRoot->nmax); amin[k] = min(amin[k],pRoot->nmin); return; } else { PushDown(pRoot); int mid = Mid(pRoot); if (b<=mid) { Query(k,pRoot->pLeft,a,b); } else if(a>mid) { Query(k,pRoot->pRight,a,b); } else { Query(k,pRoot->pLeft,a,mid); Query(k,pRoot->pRight,mid+1,b); } PushUp(pRoot); } } int r; int c; int m; int main() { while(scanf("%d%d%d",&r,&c,&m)!=EOF){ memset(nCount,0,sizeof(nCount)); for(int i=1;i<=r;i++) BuildTree(i,Tree[i],1,c+1); int id,x1,y1,x2,y2,v; while(m--){ scanf("%d",&id); if(id==1){ scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&v); for(int i=x1;i<=x2;i++) Add(Tree[i],y1,y2,v); } else if(id==2){ scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&v); for(int i=x1;i<=x2;i++) Modify(Tree[i],y1,y2,v); } else { memset(asum,0,sizeof(asum)); scanf("%d%d%d%d",&x1,&y1,&x2,&y2); int sum=0,rmax=-inf,rmin=inf; for(int i=x1;i<=x2;i++) amax[i]=-inf,amin[i]=inf; for(int i=x1;i<=x2;i++){ Query(i,Tree[i],y1,y2); sum+=asum[i]; rmax=max(rmax,amax[i]); rmin=min(rmin,amin[i]); } printf("%d %d %d\n",sum,rmin,rmax); } } } return 0; }
相关文章推荐
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法
- 基于C++实现的各种内部排序算法汇总
- C++线性时间的排序算法分析
- C++实现汉诺塔算法经典实例
- PHP实现克鲁斯卡尔算法实例解析
- C#获取关键字附近文字算法实例