您的位置:首页 > 运维架构

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倒数第二


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