zoukankan      html  css  js  c++  java
  • 线段树再练习

    要不是为了写splay的区间旋转的下放,我才不会写线段树的lazy下放来练练手(我原来的lazy都是跟着函数走的。。)

    这个时候我们得对lazy进行重新的界定,那就是lazy对当前节点是不产生影响的,而是对它的儿子产生影响。也就是说,当我到了某一个[l,r]区间,我不仅要更新它的lazy值,还要更新本身的key值,然后在对父亲节点进行更新。具体而言,在查询和修改时,访问到某一个节点,我们就得将本身的lazy值下放,同时对儿子的key值进行更新以保证我原来的下放原则。同时根据下放的原则,那么我们就会发现,这个节点的值的更新在标记下放后就不会再次在同一次操作过程中被更新,那么就直接对于这个节点的key进行更新即可。

    说那么多,还是代码比较重要!

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    typedef long long ll;
    const ll maxn = 200010;
    
    struct node{
    	ll key,lazy;
    	node *l,*r;
    	node(){
    		key = 0;lazy = 0; l = NULL; r = NULL;
    	}
    }e[maxn*3];ll ne = 0;
    
    node* build(ll l,ll r){
    	node* now = e + ne ++;
    	if(l ^ r){
    		ll mid = (l+r)>>1;
    		now->l = build(l,mid);
    		now->r = build(mid+1,r);
    	}
    	return now;
    }
    
    void pd(node* now,ll l,ll r){
    	if(now->l != 0){
    		ll mid = (l+r)>>1;
    		now->l->lazy += now->lazy; now->l->key += (mid-l+1)*now->lazy;
    		now->r->lazy += now->lazy; now->r->key += (r-mid)*now->lazy;
    		now->lazy = 0;
    	}
    }
    
    void add(node* now,ll l,ll r,ll ls,ll rs,ll v){
    	if(ls == l && r == rs){
    		now->lazy += v;
    		now->key += (r-l+1)*v;
    	}
    	else{
    		ll mid = (l+r)>>1;
    		pd(now,l,r);
    		if(ls >= mid+1) add(now->r,mid+1,r,ls,rs,v);
    		else if(rs <= mid) add(now->l,l,mid,ls,rs,v);
    		else add(now->l,l,mid,ls,mid,v),add(now->r,mid+1,r,mid+1,rs,v);
    		now->key = now->l->key + now->r->key;
    	}
    }
    
    ll ask(node* now,ll l,ll r,ll ls,ll rs){
    	if(ls == l && rs == r) return now->key;
    	else{
    		pd(now,l,r);
    		ll mid = (l+r)>>1;
    		if(ls >= mid+1) return ask(now->r,mid+1,r,ls,rs);
    		else if(rs <= mid) return ask(now->l,l,mid,ls,rs);
    		else return ask(now->l,l,mid,ls,mid)+ask(now->r,mid+1,r,mid+1,rs);
    	}
    }
    
    
    node* root;
    ll n,m;
    ll a[maxn];
    
    void test(node* now,ll l,ll r){
    	cout <<l <<" "<<r<<" "<<now->key<<" "<<now->lazy<<endl;
    	if(l^r){
    		ll mid = (l+r)>>1;
    		test(now->l,l,mid);
    		test(now->r,mid+1,r);
    	}
    }
    
    int main(){
    	freopen("cs.in","r",stdin);
    	scanf("%lld",&n);
    	root = build(1,n);
    	for(ll i = 1; i <= n; i++){
    		scanf("%lld",&a[i]);
    		add(root,1,n,i,i,a[i]);
    	}
    	scanf("%lld",&m);
    	while(m--){
    		ll temp = 0;
    		scanf("%lld",&temp);
    		if(temp == 1){
    			ll ls,rs,v;
    			scanf("%lld%lld%lld",&ls,&rs,&v);
    			add(root,1,n,ls,rs,v);
    		}
    		else if(temp == 2){
    			ll ls,rs;
    			scanf("%lld%lld",&ls,&rs);
    			printf("%lld
    ",ask(root,1,n,ls,rs));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    将数组转换为 List, 使用 Collections.addAll(arrayList, array)
    Numpy学习笔记
    sql 批量修改字段内容
    sql 查询的优化
    选择低薪喜欢的工作, 还是高薪不喜欢的工作 ?
    Tornado + Bootstrap 快速搭建自己的web应用
    sql查询出现次数最多的记录的名称和现次数以及QT聚合查找失败解决
    idea中修改git提交代码的用户名
    初识Spring Cloud与微服务
    微信小程序解析富文本的几种方法
  • 原文地址:https://www.cnblogs.com/ianaesthetic/p/3701195.html
Copyright © 2011-2022 走看看