分析
这个我们看一下数据范围,矩阵最多只有20行;
那我们就不用二维线段树了;
对于每一行开一个线段树,分别维护就行;
对于每一个查询和修改x1,x2,y1,y2,我们分别对每一行的线段树处理就行;
时间复杂度O(qnlog(m))
那么问题就转换成,对于一颗线段树,如何维护:
区间变成一个数,区间+一个数,区间查询最值和矩阵和?
其实这个题之前写过了:《迪拜的超市》
题目连接
下面还是简单分析一下:
-
需要维护哪些东西?
l, r, sum, mx, mn, add, flag(区间置为flag)
-
如何维护信息?
(1)pushup时: 这个简单,区间和,区间最值( 有多个懒标记了, 要考虑 懒标记之间的影响 和 懒标记的优先级 (最关键) 这里就不要具体分析了,直接进入poushdown 和 打懒标记时 的分析; 因为这两个是不同的,pushdown时懒标记有后效性,而打懒标记时没有; 统一分析懒标记之间的影响不太好... ) 改成下面这样分析:
(2). 直接考虑pushdown怎么维护?
(此时懒标记对于当前节点是有后效性的,要注意!) 然后考虑pushdown中懒标记的优先级。
(3). 再考虑打懒标记时要怎么维护?(这个懒标记是没有后效性的!)
这个后效性参考《迪拜的超市》的pushdown;
代码
#include<iostream>
#include<queue>
#include<cstring>
#include<vector>
#include<stdio.h>
#include<map>
#include<algorithm>
#include<deque>
#include<stack>
#include<set>
#include <unordered_map>
#include<math.h>
#include<string.h>
#define IOS ios::sync_with_stdio(false),cin.tie(0);
using namespace std;
#define pb push_back
#define coutl cout<<"------------"<<endl;
#define fi first
#define se second
#define ire(x) scanf("%d",&x)
#define iire(a,b) scanf("%d %d",&a,&b)
#define lre(x) scanf("%lld",&x)
#define llre(a,b) scanf("%lld %lld",&a,&b)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define endl "\n"
#define PI acos(-1.0)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<double, int> PDI;
typedef pair<ll, ll> PLL;
typedef pair<double, double> PDD;
typedef pair<double, pair<int, double>> PDID;
typedef pair<char, char> PCC;
typedef pair<char, pair<int, int> > PCII;
typedef pair<int, pair<int, int> > PIII;
typedef pair<int, pair<int, pair<int, int> > > PIIII;
typedef pair<ll, pair<int, int> > PLII;
const int maxn = 5e5 + 7;
const int N = 2010 + 7;
const int M = 1e6 + 7;
const int mod = 998244353;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double pi = acos(-1);
const double eps = 1e-8;
ll gcd(ll a,ll b) {return b==0 ? a : gcd(b,a%b);}
ll lcm(ll a,ll b) {return a*b / gcd(a,b);}
ll qmi(ll a,ll b,ll p) {ll ans = 1; while(b) { if(b & 1) ans = ans * a % p; a = a * a % p; b >>= 1; } return ans;}
int lowbit(int x) {return x & (-x);}
struct node
{
int l,r;
ll sum;
int mx;
int mn;
ll add; //区间+懒标记
int flag; //区间覆盖懒标记(初始化为-1)
}tr[22][maxn * 4];
int n,m,q;
ll sum;
int mx,mn;
void pushup(int u,int id)
{
tr[id][u].sum = tr[id][u<<1].sum + tr[id][u<<1|1].sum;
tr[id][u].mx = max(tr[id][u<<1].mx , tr[id][u<<1|1].mx);
tr[id][u].mn = min(tr[id][u<<1].mn , tr[id][u<<1|1].mn);
}
//区间覆盖的标记优先级比较大
void pushdown(int u,int id)
{
if(tr[id][u].flag != -1) //先更新cl标记, 需要清空
{
tr[id][u<<1].flag = tr[id][u].flag;
tr[id][u<<1].sum = (ll)(tr[id][u<<1].r - tr[id][u<<1].l + 1) * tr[id][u].flag;
tr[id][u<<1].mn = tr[id][u<<1].mx = tr[id][u].flag;
tr[id][u<<1].add = 0;
tr[id][u<<1|1].flag = tr[id][u].flag;
tr[id][u<<1|1].sum = (ll)(tr[id][u<<1|1].r - tr[id][u<<1|1].l + 1) * tr[id][u].flag;
tr[id][u<<1|1].mn = tr[id][u<<1|1].mx = tr[id][u].flag;
tr[id][u<<1|1].add = 0;
tr[id][u].flag = -1;
}
if(tr[id][u].add) //需要加
{
tr[id][u<<1].add += tr[id][u].add;
tr[id][u<<1].sum += (ll)(tr[id][u<<1].r - tr[id][u<<1].l + 1) * tr[id][u].add;
tr[id][u<<1].mx += tr[id][u].add;
tr[id][u<<1].mn += tr[id][u].add;
tr[id][u<<1|1].add += tr[id][u].add;
tr[id][u<<1|1].sum += (ll)(tr[id][u<<1|1].r - tr[id][u<<1|1].l + 1) * tr[id][u].add;
tr[id][u<<1|1].mx += tr[id][u].add;
tr[id][u<<1|1].mn += tr[id][u].add;
tr[id][u].add = 0;
}
}
void build(int u,int l,int r,int id) //建树
{
tr[id][u] = {l,r};
tr[id][u].flag = -1;
if(l == r)
{
tr[id][u] = {l,r,0,0,0,0,-1};
return;
}
int mid = l + r >> 1;
build(u<<1, l, mid,id);
build(u<<1|1, mid+1, r,id);
pushup(u,id);
}
void update1(int u,int l,int r,int v,int id) //区间+x
{
if(l > r) return;
if(tr[id][u].l >= l && tr[id][u].r <= r)
{
//注意add是没有包括自己区间的哦
tr[id][u].sum += (ll)(tr[id][u].r - tr[id][u].l + 1) * v;
tr[id][u].mx += v;
tr[id][u].mn += v;
tr[id][u].add += v;
return;
}
pushdown(u,id); //分裂了,下传懒标记
int mid = tr[id][u].l + tr[id][u].r >> 1;
if(l <= mid) update1(u<<1, l, r, v,id);
if(r > mid) update1(u<<1|1, l, r, v,id);
pushup(u,id); //向上更新
}
void update2(int u,int l,int r,int v,int id) //区间+x
{
if(l > r) return;
if(tr[id][u].l >= l && tr[id][u].r <= r)
{
//注意add是没有包括自己区间的哦
tr[id][u].sum = (ll)(tr[id][u].r - tr[id][u].l + 1) * v;
tr[id][u].mx = v;
tr[id][u].mn = v;
tr[id][u].flag = v;
tr[id][u].add = 0;
return;
}
pushdown(u,id); //分裂了,下传懒标记
int mid = tr[id][u].l + tr[id][u].r >> 1;
if(l <= mid) update2(u<<1, l, r, v,id);
if(r > mid) update2(u<<1|1, l, r, v,id);
pushup(u,id); //向上更新
}
void query(int u,int l,int r,int id)
{
if(tr[id][u].l >= l && tr[id][u].r <= r)
{
sum += tr[id][u].sum;
mx = max(mx,tr[id][u].mx);
mn = min(mn,tr[id][u].mn);
return;
}
pushdown(u,id); //分裂了,下传懒标记
int mid = tr[id][u].l + tr[id][u].r >> 1;
if(l <= mid) query(u<<1, l, r, id);
if(r > mid) query(u<<1|1, l, r, id);
}
int main()
{
while(scanf("%d %d %d",&n,&m,&q) != EOF)
{
for(int i=1;i<=n;i++) build(1,1,m,i); //每一行建树
while(q--)
{
int op;
ire(op);
int x1,x2,y1,y2,val;
if(op == 1) //区间+
{
iire(x1,y1);
iire(x2,y2);
ire(val);
for(int i=x1;i<=x2;i++) update1(1,y1,y2,val,i);
}
else if(op == 2) //区间覆盖
{
iire(x1,y1);
iire(x2,y2);
ire(val);
for(int i=x1;i<=x2;i++) update2(1,y1,y2,val,i);
}
else //矩阵查询
{
iire(x1,y1);
iire(x2,y2);
//初始化
sum = 0; mn = inf; mx = -inf;
for(int i=x1;i<=x2;i++) query(1,y1,y2,i);
printf("%lld %d %d\n",sum,mn,mx);
}
}
}
return 0;
}