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;
    }
    
  • 相关阅读:
    Android Matrix(坐标矩阵)
    Android 修改底部导航栏navigationbar的颜色
    Java跨平台原理
    Java的平台无关性
    AudioManager --- generateAudioSessionId
    Android中使用logwrapper来重定向应用程序的标准输出
    Linux指令
    HLS -- m3u8档案格式解析
    新購電腦筆記
    Android多媒体--MediaCodec 中文API文档
  • 原文地址:https://www.cnblogs.com/ianaesthetic/p/3701195.html
Copyright © 2011-2022 走看看