题意
对矩阵有三种操作,第一是让矩阵的每个元素加上某个数,第二是让矩阵得每个元素变成某个数,第三是输出某个子矩阵的数字总和,最大值和最小值。开始时,矩阵得每个元素为0.
思路
因为最多只有20行,所以可以每行都建立一个线段树,问题是注意set操作和add操作之间的联系,set是优先于add的。我在pushdown函数中就因为没注意这个问题,WA到怀疑人生。
#include<bits/stdc++.h>
using namespace std;
const int N = 501000;
struct Node{
int sum,mini,maxi,add,seti;
}tree[21][N << 2];
const int inf = 0x3f3f3f3f;
int miner,maxer,sum;
void maketree(int node,int begin,int end, Node tree[])
{
tree[node].add = 0;
tree[node].seti = 0;
if(begin == end)
{
tree[node].mini = tree[node].maxi = tree[node].sum = 0;
return;
}
int mid = (begin + end) / 2;
maketree(node << 1,begin,mid ,tree);
maketree(node << 1|1,mid + 1,end ,tree);
tree[node].maxi = tree[node].mini = tree[node].seti = 0;
}
void pushdown(int node,int begin,int end,Node tree[])
{
if(tree[node].seti != 0)
{
int mid = ( begin + end) / 2;
tree[node << 1].sum = (mid - begin + 1) * tree[node].seti;
tree[node << 1 | 1].sum = (end - mid) * tree[node].seti;
tree[node << 1].add = tree[node].seti;
tree[node << 1|1].add = tree[node].seti;
tree[node << 1].maxi = tree[node].seti;
tree[node << 1|1].maxi = tree[node].seti;
tree[node << 1].mini = tree[node].seti;
tree[node << 1|1].mini = tree[node].seti;
tree[node << 1].add = tree[node << 1|1].add = 0;
tree[node << 1].seti = tree[node << 1|1].seti = tree[node].seti;
tree[node].seti = 0;
}
if(tree[node].add != 0)
{
int mid = ( begin + end) / 2;
tree[node << 1].sum += (mid - begin + 1) * tree[node].add;
tree[node << 1 | 1].sum += (end - mid) * tree[node].add;
tree[node << 1].add += tree[node].add;
tree[node << 1|1].add += tree[node].add;
tree[node << 1].maxi += tree[node].add;
tree[node << 1|1].maxi += tree[node].add;
tree[node << 1].mini += tree[node].add;
tree[node << 1|1].mini += tree[node].add;
tree[node].add = 0;
}
}
void add(int node,int begin,int end,int l,int r ,int v,Node tree[])
{
if(l > end || r < begin )
return ;
if(begin >= l && end <= r)
{
tree[node].sum += (end - begin + 1)* v;
tree[node].maxi += v;
tree[node].mini += v;
tree[node].add += v;
return;
}
pushdown(node,begin,end,tree);
int mid = (begin + end) / 2;
add(node << 1,begin,mid ,l,r,v,tree);
add(node << 1|1,mid + 1, end,l,r,v,tree);
tree[node].maxi = max(tree[node << 1].maxi,tree[node << 1|1].maxi);
tree[node].mini = min(tree[node << 1].mini,tree[node << 1|1].mini);
tree[node].sum = tree[node << 1].sum + tree[node << 1|1].sum;
}
void seti(int node,int begin,int end,int l,int r,int v,Node tree[])
{
if(l > end || r < begin)
return;
if(begin >= l && end <= r)
{
tree[node].sum = (end - begin + 1) * v;
tree[node].maxi = v;
tree[node].mini = v;
tree[node].add = 0;
tree[node].seti = v;
return;
}
pushdown(node,begin,end,tree);
int mid = (begin + end) / 2;
seti(node << 1,begin,mid ,l,r,v,tree);
seti(node << 1|1,mid + 1, end,l,r,v,tree);
tree[node].maxi = max(tree[node << 1].maxi,tree[node << 1|1].maxi);
tree[node].mini = min(tree[node << 1].mini,tree[node << 1|1].mini);
tree[node].sum = tree[node << 1].sum + tree[node << 1|1].sum;
}
void query(int node,int begin ,int end,int l,int r,Node tree[])
{
if(l > end || r < begin )
return;
if(l <= begin && r >= end)
{
miner = min(miner,tree[node].mini);
maxer = max(maxer,tree[node].maxi);
sum += tree[node].sum;
return;
}
pushdown(node,begin,end,tree);
int mid = (begin + end) / 2;
query(node << 1,begin ,mid ,l, r ,tree);
query(node << 1|1,mid + 1,end ,l,r ,tree);
}
int main()
{
int n,m,k,i,x1,y1,y2,x2,v,A,j;
while(~scanf("%d %d %d",&n,&m,&k))
{
for(i = 1; i <= n ;i++)
maketree(1,1,m,tree[i]);
for(j = 1; j <= k ; j++)
{
scanf("%d",&A);
if(A == 1)
{
scanf("%d %d %d %d %d",&x1,&y1,&x2,&y2,&v);
for(i = x1; i <= x2 ;i++ )
{
add(1,1,m,y1,y2,v,tree[i]);
}
}
else if(A == 2)
{
scanf("%d %d %d %d %d",&x1,&y1,&x2,&y2,&v);
for(i = x1 ;i <= x2 ;i++)
{
seti(1,1,m,y1,y2,v,tree[i]);
}
}
else if(A == 3)
{
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
miner = inf;
maxer = -1;
sum = 0;
for(i = x1 ;i <= x2 ;i++)
{
query(1,1,m,y1,y2,tree[i]);
}
printf("%d %d %d\n",sum,miner,maxer);
}
}
}
return 0;
}