• [复习]线段树基础


    大部分题目是纯模板,只写一下《山海经》
    题意:查询区间最大字段和(不带修)
    考虑区间最大子段和由哪里贡献得到,
    可能是lson的ans,rson的ans,也可以是lson与rson拼接而成
    只需要抽象出加法(push_up)操作,就很好理解了
    网上题解太麻烦, 需要各种分类讨论,容易写挂
    所以直接抽象出加法即可
    维护4个range:左侧最大和lm、右侧最大和rm、总和sum、最大子段和ans
    \(ans = max(lm+rm, l.ans, r.ans)\)
    然后套路维护剩下的\(lm rm sum\)即可
    需要注意的几个地方:区间为空时候要特判一下即可
    即:区间为空的时候区间加法的l,r会挂掉,然后区间加之前需要判断是否为空区间

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cassert>
    const int N = 1e5+10, TR = 4*N;
    int a[N];
    int n, q;
    struct rg_t{
    	int val, l, r;
    	rg_t(){r = -1;val = 0, l = 1;}
    	rg_t(int val_, int l_, int r_):val(val_), l(l_), r(r_){}
    	friend bool operator <(const rg_t& x, const rg_t& y){
    		if(y.empty()) return false;
    		if(x.empty()) return true;
    		if(x.val != y.val) return x.val < y.val;
    		if(x.l != y.l) return x.l>y.l;
    		return x.r > y.r;
    	}
    	bool empty()const{
    		return r==-1;
    	}
    	void make_empty(){
    		r = -1;
    	}
    	friend rg_t operator +(const rg_t& x, const rg_t& y){
    		if(y.empty()) return x;
    		if(x.empty()) return y;
    		return rg_t(x.val+y.val, x.l, y.r);
    	}
    };
    struct segment_tree{
    	struct node{
    		rg_t ans, lm, rm, sum;
    		//sum:总和 
    		node(){}
    		node(int val, int u){
    			ans = sum = rg_t(val, u, u);
    			if(val > 0) lm = rm = sum;
    		}
    		node(rg_t ans_, rg_t lm_, rg_t rm_, rg_t sum_):ans(ans_), lm(lm_), rm(rm_),sum(sum_) {}
    		bool empty(){
    			return sum.empty();
    		}
    		friend node operator +(const node& a, const node& b){
    			if(b.empty()) return a;
    			if(a.empty()) return b;
    			node c; 
    			c.ans = std::max(std::max(a.ans, b.ans), a.rm+b.lm);
    			c.sum = a.sum+b.sum;
    			rg_t tlm, trm;
    			tlm = a.sum+b.lm, trm = a.rm+b.sum;
    			if(b.lm.empty()) tlm = a.sum, tlm.r = b.sum.r;
    			if(a.rm.empty()) trm = b.sum, tlm.l = a.sum.l;
    			c.lm = std::max(a.lm, tlm);
    			c.rm = std::max(b.rm, trm);
    			return c;
    		}
    	}tree[TR];
    	void update(int rt, int val, int l){
    		tree[rt] = node(val, l);
    	}
    	void push_up(int rt){ 
    		tree[rt] = tree[rt<<1]+tree[rt<<1|1];
    	}
    	void build(int rt, int l, int r){
    		if(l == r) return update(rt, a[l], l);
    		int mid = (l+r)>>1;
    		build(rt<<1, l, mid);
    		build(rt<<1|1, mid+1, r);
    		push_up(rt);
    	}
    	node query(int rt, int l, int r, int s, int t){ 
    		if(s <= l && r <= t) return tree[rt];
    		int mid = (l+r)>>1;
    		node a,b;
    		if(s <= mid)a = query(rt<<1, l, mid, s, t);
    		if(t > mid) b = query(rt<<1|1, mid+1, r, s, t);
    		return a+b;
    	}
    }segt;
    int main(){
    	scanf("%d%d", &n, &q);
    	for(int i = 1; i <= n; ++i){
    		scanf("%d", a+i);
    	}
    	segt.build(1 ,1, n);
    	for(int i = 1; i <= q; ++i){
    		int l, r; scanf("%d%d", &l, &r);
    		rg_t ans = segt.query(1, 1, n, l ,r).ans;
    		printf("%d %d %d\n", ans.l, ans.r, ans.val);
    	}
    	return 0;
    }
    
  • 相关阅读:
    数据库查找
    关于购买功能的相关学习
    信息登记功能例子
    总结
    团队作业
    团队作业
    团队作业
    团队作业
    团队作业
    第一节:库的管理
  • 原文地址:https://www.cnblogs.com/cdsidi/p/15824916.html
Copyright © 2020-2023  润新知