UVA11992二维线段树区间修改

61 篇文章 0 订阅
10 篇文章 0 订阅
#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;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值