• 线段树再练习


    要不是为了写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;
    }
    
  • 相关阅读:
    poj 2187 Beauty Contest(旋转卡壳)
    poj 2540 Hotter Colder(极角计算半平面交)
    poj 1279 Art Gallery(利用极角计算半平面交)
    poj 3384 Feng Shui(半平面交的联机算法)
    poj 1151 Atlantis(矩形面积并)
    zoj 1659 Mobile Phone Coverage(矩形面积并)
    uva 10213 How Many Pieces of Land (欧拉公式计算多面体)
    uva 190 Circle Through Three Points(三点求外心)
    zoj 1280 Intersecting Lines(两直线交点)
    poj 1041 John's trip(欧拉回路)
  • 原文地址:https://www.cnblogs.com/ianaesthetic/p/3701195.html
Copyright © 2020-2023  润新知