UVA11992 Fast Matrix Operations
传送门:
https://www.luogu.com.cn/problem/UVA11992
蓝书(训练指南)的线段树例题。
分析
这题在思维上并不复杂,是线段树的常见操作。
需要注意的地方主要是标记优先级:
这里我像蓝书一样记增加标记为 \(addv\),赋值标记记为 \(setv\)。
当遇到赋值操作的时候,相应节点的 \(addv\) 需要进行清零,因为当你下传 \(setv\) 的过程中的子节点的 \(addv\) 都会被覆盖掉。
然后查询因为信息比较多,我比较推荐直接返回区间合并得到的全部信息,这样可以少写很多函数。
吐槽:
写的时候看反 op1, op2
了,还有把书上的 \(m\) 误以为是列数,我自裁。
不过交一发就到了最优解前列hh
#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define debug(x) cerr << #x << ": " << x << endl
#define pb push_back
#define eb emplace_back
#define set0(a) memset(a,0,sizeof(a))
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define INF 0x3f3f3f3f
inline void read(int &x) {
int s=0;x=1;
char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')x=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
x*=s;
}
#define y1 Tenshi
const int N=1e6+10;
struct SegTree{
struct Node{
int l, r;
int sum, v[2];
#define ls(u) u<<1
#define rs(u) u<<1|1
}tr[N<<2];
int len[N<<2];
int addv[N<<2], setv[N<<2];
Node merge(Node a, Node b){
return {a.l, b.r, a.sum+b.sum, min(a.v[0], b.v[0]), max(a.v[1], b.v[1])};
}
void F(int u, int op, int v){
if(op==0){
addv[u]=0, setv[u]=v;
tr[u].sum=len[u]*v, tr[u].v[0]=tr[u].v[1]=v;
}
else{
addv[u]+=v;
tr[u].sum+=len[u]*v, tr[u].v[0]+=v, tr[u].v[1]+=v;
}
}
void pushdown(int u){
if(~setv[u]){
F(ls(u), 0, setv[u]), F(rs(u), 0, setv[u]);
setv[u]=-1;
}
if(addv[u]){
F(ls(u), 1, addv[u]), F(rs(u), 1, addv[u]);
addv[u]=0;
}
}
void build(int u, int l, int r){
len[u]=r-l+1, setv[u]=-1;
if(l==r) return tr[u]={l, r}, void();
int mid=l+r>>1;
build(ls(u), l, mid), build(rs(u), mid+1, r);
tr[u]=merge(tr[ls(u)], tr[rs(u)]);
}
Node query(int u, int l, int r){
if(tr[u].l>=l && tr[u].r<=r) return tr[u];
int mid=tr[u].l+tr[u].r>>1;
Node L={-1}, R={-1};
pushdown(u);
if(mid>=l) L=query(ls(u), l, r);
if(mid<r) R=query(rs(u), l, r);
if(L.l==-1) return R; if(R.l==-1) return L;
return merge(L, R);
}
void upd(int u, int l, int r, int v, int op){
if(tr[u].l>=l && tr[u].r<=r){
F(u, op, v);
return;
}
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
if(mid>=l) upd(ls(u), l, r, v, op);
if(mid<r) upd(rs(u), l, r, v, op);
tr[u]=merge(tr[ls(u)], tr[rs(u)]);
}
};
int n, m, q;
int main(){
while(cin>>n>>m>>q){
SegTree* tree=new SegTree[n+1];
rep(i,1,n) tree[i].build(1, 1, m);
while(q--){
int op; read(op);
int x1, y1, x2, y2; read(x1), read(y1), read(x2), read(y2);
if(op==1){
int v; read(v);
rep(i,x1,x2) tree[i].upd(1, y1, y2, v, 1);
}
else if(op==2){
int v; read(v);
rep(i,x1,x2) tree[i].upd(1, y1, y2, v, 0);
}
else if(op==3){
int sum=0, mn=INF, mx=0;
rep(i,x1,x2){
auto res=tree[i].query(1, y1, y2);
sum+=res.sum, mn=min(mn, res.v[0]), mx=max(mx, res.v[1]);
}
cout<<sum<<' '<<mn<<' '<<mx<<endl;
}
}
}
return 0;
}