Uva-11992-Fast Matrix Operations

本文深入探讨了线段树在矩阵操作中的应用,详细介绍了三种核心操作:区域元素增益、区域元素赋值以及区域元素求和。通过实例演示,旨在帮助读者理解线段树在解决此类问题时的高效性和灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个题是一道线段树题,要求进行区间修改设置以及求和。

大意是说给你一个矩阵,然后有3种操作:

1  x1 y1 x2 y2 val是将矩阵x1 y1 x2 y2的区间内的值全部增加val

2 x1 y1 x2 y2 val是将矩阵x1 y1 x2 y2的区间内的值全部设置为val

3 x1 y1 x2 y2 求出x1 y1 x2 y2的区间内的和,最大值,最小值。

从题目中的描述和要求可以看出这个题属于线段树题,而且要进行区间的操作,其中注意x,y与行列的对应,我最初在这里弄反了,导致一直RE和WA,悲剧~

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define MAX 3000100
using namespace std;
struct node
{
    int l,r;
    int mini,maxi,sum;
    int add,set;
}a[MAX];
int anssum,ansmin,ansmax,r,c,m;
const int inf=1000000009;
void built(int l,int r,int index)
{
    a[index].l=l;a[index].r=r;a[index].add=0;a[index].set=-1;a[index].sum=a[index].mini=a[index].maxi=0;
    if(l==r)
	return;
    int mid=l+(r-l)/2;
    built(l,mid,index<<1);built(mid+1,r,index<<1|1);
}
void pushdown(int index)
{
    if(a[index].l>=a[index].r)
	return;
    if(a[index].set!=-1)
    {
	a[index<<1].set=a[index<<1|1].set=a[index].set;
	a[index<<1].mini=a[index<<1|1].mini=a[index].set;
	a[index<<1].maxi=a[index<<1|1].maxi=a[index].set;
	a[index<<1].add=a[index<<1|1].add=0;
	a[index<<1].sum=(a[index<<1].r-a[index<<1].l+1)*a[index].set;
	a[index<<1|1].sum=(a[index<<1|1].r-a[index<<1|1].l+1)*a[index].set;
    }
    if(a[index].add>0)
    {
	int ita=a[index].add;
	a[index<<1].add+=ita;a[index<<1|1].add+=ita;
	a[index<<1].mini+=ita;a[index<<1|1].mini+=ita;
	a[index<<1].maxi+=ita;a[index<<1|1].maxi+=ita;
	a[index<<1].sum+=ita*(a[index<<1].r-a[index<<1].l+1);
	a[index<<1|1].sum+=ita*(a[index<<1|1].r-a[index<<1|1].l+1);
    }
}
void maintain(int index)
{
    if(a[index].l>=a[index].r)
	return;
    a[index].maxi=max(a[index<<1].maxi,a[index<<1|1].maxi);
    a[index].mini=min(a[index<<1].mini,a[index<<1|1].mini);
    a[index].sum=a[index<<1].sum+a[index<<1|1].sum;
}
void updateSet(int L,int R,int val,int index)
{
    if(a[index].l==L&&a[index].r==R)
    {
	a[index].set=val;
	a[index].maxi=val;
	a[index].mini=val;
	a[index].add=0;
	a[index].sum=(a[index].r-a[index].l+1)*val;
	return;
    }
    pushdown(index);
    a[index].set=-1;
    a[index].add=0;
    int mid=a[index].l+(a[index].r-a[index].l)/2;
    if(R<=mid)
	updateSet(L,R,val,index<<1);
    else if(L>mid)
	updateSet(L,R,val,index<<1|1);
    else
    {
	updateSet(L,mid,val,index<<1);
	updateSet(mid+1,R,val,index<<1|1);
    }
    maintain(index);
}
void updateAdd(int L,int R,int val,int index)
{
    if(a[index].l==L&&a[index].r==R)
    {
	a[index].add+=val;
	a[index].maxi+=val;
	a[index].mini+=val;
	a[index].sum+=(a[index].r-a[index].l+1)*val;
	return ;
    }
    pushdown(index);
    a[index].set=-1;
    a[index].add=0;
    int mid=a[index].l+(a[index].r-a[index].l)/2;
    if(R<=mid)
	updateAdd(L,R,val,index<<1);
    else if(L>mid)
	updateAdd(L,R,val,index<<1|1);
    else
    {
	updateAdd(L,mid,val,index<<1);
	updateAdd(mid+1,R,val,index<<1|1);
    }
    maintain(index);
}
void Query(int L,int R,int index)
{
    if(a[index].l==L&&a[index].r==R)
    {
	anssum+=a[index].sum;
	ansmin=min(ansmin,a[index].mini);
	ansmax=max(ansmax,a[index].maxi);
	return;
    }
    pushdown(index);
    a[index].set=-1;
    a[index].add=0;
    int mid=a[index].l+(a[index].r-a[index].l)/2;
    if(R<=mid)
	Query(L,R,index<<1);
    else if(L>mid)
	Query(L,R,index<<1|1);
    else
    {
	Query(L,mid,index<<1);
	Query(mid+1,R,index<<1|1);
    }
    maintain(index);
}
int main()
{
    while(scanf("%d%d%d",&r,&c,&m)!=EOF)
    {
	built(1,r*c,1);
	int op,x1,x2,y1,y2,val;
	while(m--)
	{
	    scanf("%d",&op);
	    if(op==1)
	    {
		scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&val);
		for(int i=x1;i<=x2;i++)
		    updateAdd((i-1)*c+y1,(i-1)*c+y2,val,1);
	    }
	    else if(op==2)
	    {
		scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&val);
		for(int i=x1;i<=x2;i++)
		    updateSet((i-1)*c+y1,(i-1)*c+y2,val,1);
	    }
	    else
	    {
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		anssum=0;ansmin=inf;ansmax=-inf;
		for(int i=x1;i<=x2;i++)
		    Query((i-1)*c+y1,(i-1)*c+y2,1);
		printf("%d %d %d\n",anssum,ansmin,ansmax);
	    }
	}
    }
    return 0;
}


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值