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 '
'
#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;
}
原文地址:https://www.cnblogs.com/Tenshi/p/15220788.html