您的位置:首页 > 编程语言 > Go语言

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息