这是一道貌似二维的线段树题,其实会发现二维不能做,要转换为一维。题意:有一个r行c列的矩阵里面有最多不超过10^6个元素,每个元素的位置(x,y)且1<=x<=r,1<=y<=c。最初所有元素都为0,你有三种操作:
1,将子矩阵(x1,y1,x2,y2)中所有的元素都增加v;
2,将子矩阵(x1,y1,x2,y2)中所有元素都设置为v;
3,输出子矩阵(x1,y1,x2,y2)中所有元素的和以及最小元素和最大元素的值。
在Input中的隐含条件:矩阵最多不超过20行,也就是说r<=20。
我的解题思路:本来想开个二维的线段树,第一维长度是20,第二维长度是10^6 × 4。结果发现内存开不下了……没办法只能转换成一维了,其实一维还好一些。转换成一维以后,由于有两种延迟标记set和add,所以这里面的问题也需要仔细探讨。由于set操作不受前面的操作的影响(也就是说一个矩阵无论之前有多少次不同种类的操作,在set操作之后也只是相当于只做了该次set操作而已),我们假设认为是set操作优先级最高,所以set操作不但要覆盖以前的set操作,还要覆盖add操作(其实就是覆盖所有操作)。而add操作受以前操作的影响,所以直接添加add操作就好。到时候更新节点时两个延迟操作标记同时存在,先做set操作,再做add操作就可以了。
我的解题代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <cctype>
#include <ctime>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <list>
#include <map>
using namespace std;
#define N 1000000
struct tree //定义线段树结构体
{
int left, right, mid;
int set, add; //两个延迟标记
int minvalue, maxvalue, sumvalue;
void init()
{
mid = (left + right) >> 1;
add = minvalue = maxvalue = sumvalue = 0;
set = INT_MAX;
return;
}
};
tree node[N<<2];
int r, c, m;
int sumans, maxans, minans;
void BuildTree(int left, int right, int x); //建立线段树
void Query(int left, int right, int x); //3操作
void Set(int left, int right, int v, int x); //2操作
void Add(int left, int right, int v, int x); //1操作
void PushUp(int x); //向上更新
void PushDown(int x); //向下更新
int main()
{
int que, x1, x2, y1, y2, v;
while (~scanf("%d %d %d", &r, &c, &m))
{
BuildTree(1, r * c, 1);
while (m--)
{
scanf("%d %d %d %d %d", &que, &x1, &y1, &x2, &y2);
if (x1 > x2) swap(x1, x2);
if (y1 > y2) swap(y1, y2);
if (que == 3)
{
//先初始化要输出的答案
sumans = 0;
maxans = -INT_MAX;
minans = INT_MAX;
//分段询问并存储答案
for (int i=x1; i<=x2; ++i) Query((i - 1) * c + y1, (i - 1) * c + y2, 1);
printf("%d %d %d\n", sumans, minans, maxans);
continue;
}
scanf("%d", &v);
if (que == 2)
{
for (int i=x1; i<=x2; ++i) Set((i - 1) * c + y1, (i - 1) * c + y2, v, 1);
}
else
{
for (int i=x1; i<=x2; ++i) Add((i - 1) * c + y1, (i - 1) * c + y2, v, 1);
}
}
}
return 0;
}
void BuildTree(int left, int right, int x)
{
node[x].left = left;
node[x].right = right;
node[x].init();
if (left == right) return;
BuildTree(left, node[x].mid, x << 1);
BuildTree(node[x].mid + 1, right, x << 1 | 1);
return;
}
void Query(int left, int right, int x)
{
if (node[x].left == left && node[x].right == right)
{
sumans += node[x].sumvalue;
maxans = max(maxans, node[x].maxvalue);
minans = min(minans, node[x].minvalue);
return;
}
if (node[x].set != INT_MAX || node[x].add != 0) PushDown(x);
if (right <= node[x].mid)
{
Query(left, right, x << 1);
}
else if (left > node[x].mid)
{
Query(left, right, x << 1 | 1);
}
else
{
Query(left, node[x].mid, x << 1);
Query(node[x].mid + 1, right, x << 1 | 1);
}
return;
}
void Set(int left, int right, int v, int x)
{
if (node[x].left == left && node[x].right == right)
{
node[x].maxvalue = node[x].minvalue = v;
node[x].sumvalue = (right - left + 1) * v;
node[x].set = v;
node[x].add = 0; //set操作优先级高,add操作也要被覆盖
PushUp(x);
return;
}
if (node[x].add != 0 || node[x].set != INT_MAX) PushDown(x);
if (right <= node[x].mid)
{
Set(left, right, v, x << 1);
}
else if (left > node[x].mid)
{
Set(left, right, v, x << 1 | 1);
}
else
{
Set(left, node[x].mid, v, x << 1);
Set(node[x].mid + 1, right, v, x << 1 | 1);
}
return;
}
void Add(int left, int right, int v, int x)
{
if (node[x].left == left && node[x].right == right)
{
node[x].maxvalue += v;
node[x].minvalue += v;
node[x].sumvalue += v * (right - left + 1);
node[x].add += v;
PushUp(x);
return;
}
if (node[x].add != 0 || node[x].set != INT_MAX) PushDown(x);
if (right <= node[x].mid)
{
Add(left, right, v, x << 1);
}
else if (left > node[x].mid)
{
Add(left, right, v, x << 1 | 1);
}
else
{
Add(left, node[x].mid, v, x << 1);
Add(node[x].mid + 1, right, v, x << 1 | 1);
}
return;
}
void PushUp(int x)
{
while (x != 1)
{
x >>= 1;
node[x].sumvalue = node[x<<1].sumvalue + node[x<<1|1].sumvalue;
node[x].maxvalue = max(node[x<<1].maxvalue, node[x<<1|1].maxvalue);
node[x].minvalue = min(node[x<<1].minvalue, node[x<<1|1].minvalue);
}
return;
}
void PushDown(int x)
{
if (node[x].left == node[x].right)
{
node[x].add = 0;
node[x].set = INT_MAX;
return;
}
if (node[x].set != INT_MAX) //先进行set操作
{
node[x<<1].set = node[x<<1|1].set = node[x].set;
node[x<<1].add = node[x<<1|1].add = 0;
node[x<<1].sumvalue = (node[x<<1].right - node[x<<1].left + 1) * node[x].set;
node[x<<1|1].sumvalue = (node[x<<1|1].right - node[x<<1|1].left + 1) * node[x].set;
node[x<<1].minvalue = node[x<<1].maxvalue = node[x].set;
node[x<<1|1].minvalue = node[x<<1|1].maxvalue = node[x].set;
node[x].set = INT_MAX;
}
if (node[x].add != 0)
{
node[x<<1].add += node[x].add;
node[x<<1|1].add += node[x].add;
node[x<<1].sumvalue += node[x].add * (node[x<<1].right - node[x<<1].left + 1);
node[x<<1|1].sumvalue += node[x].add * (node[x<<1|1].right - node[x<<1|1].left + 1);
node[x<<1].maxvalue += node[x].add;
node[x<<1|1].maxvalue += node[x].add;
node[x<<1].minvalue += node[x].add;
node[x<<1|1].minvalue += node[x].add;
node[x].add = 0;
}
return;
}