zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    okhttp连接池:put,get方法&connection回收
    okhttp拦截器之ConnectInterceptor解析
    okhttp拦截器之CacheInterceptor解析
    okhttp缓存策略源码分析:put&get方法
    java线程基础巩固---ThreadGroup API学习
    通过JDBC驱动加载深刻理解线程上下文类加载器机制
    线程上下文类加载器实战分析与难点剖析
    ServiceLoader在SPI中的重要作用分析
    小试牛刀【龙哥翻译】
    小试牛刀【自己翻译】
  • 原文地址:https://www.cnblogs.com/Tenshi/p/15220788.html
Copyright © 2011-2022 走看看