zoukankan      html  css  js  c++  java
  • 线段树二分

    线段树二分 - Luogu P5579 [PA2015] - Siano

    经过排序后,每次操作都可以转化为一个连续区间。在割草时,只需要查询最小的高于v的草,然后修改从它开始的整个后缀区间。本题难点在于如果查询最小的高于v的草,如果简单的用二分内套线段树单点查询,是logn * logn的复杂度,会T。如果在线段树中维护区间最小草长,可以写出logn的算法来实现这个查询。(见find函数)。

    本题一切均建立在这样一个特殊条件下:线段树维护的区间是非递减区间

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 5+10;
    typedef long long ll;
    int n, m;
    ll k, v;
    ll a[N];
    struct Node{
    	ll inc; // 该区间的单日增长
    	ll sum; // 该区间的总长度
    	ll minv; // 该区间的最小草长 = 左子区间的最小草长 
    	ll lazy; // 增长天数
    	ll setlazy; // 剪为v
    }tr[N<<2];
    
    
    void build(int rt, int l, int r){
    	tr[rt].sum = 0;
    	tr[rt].minv = 0;
    	tr[rt].lazy = 0;
    	tr[rt].setlazy = -1;
    	if(l==r){
    		tr[rt].inc = a[l];
    	}else{
    		int mid = l+r>>1;
    		build(rt<<1, l, mid);
    		build(rt<<1|1, mid+1, r);
    		tr[rt].inc = tr[rt<<1].inc + tr[rt<<1|1].inc;
    	}
    }
    
    void push_up(int rt){
        tr[rt].sum = tr[rt<<1].sum + tr[rt<<1|1].sum;
        tr[rt].minv = tr[rt<<1].minv;
    }
    
    void push_down(int rt, int l, int r){
    	if(tr[rt].setlazy != -1){
    		int mid = l+r>>1;
    		tr[rt<<1].sum = (mid-l+1) * tr[rt].setlazy;
    		tr[rt<<1|1].sum = (r-mid) * tr[rt].setlazy;
    		tr[rt<<1].minv = tr[rt<<1|1].minv = tr[rt].setlazy;
    		tr[rt<<1].setlazy = tr[rt<<1|1].setlazy = tr[rt].setlazy;
    		tr[rt<<1].lazy = tr[rt<<1|1].lazy = 0;
    		tr[rt].setlazy = -1;
    	}
    
    	if(tr[rt].lazy){
    		int mid = l+r>>1;
    		tr[rt<<1].sum += tr[rt<<1].inc * tr[rt].lazy;
    		tr[rt<<1|1].sum += tr[rt<<1|1].inc * tr[rt].lazy;
    		tr[rt<<1].lazy += tr[rt].lazy;
    		tr[rt<<1|1].lazy += tr[rt].lazy;
    		tr[rt<<1].minv += a[l] * tr[rt].lazy;
    		tr[rt<<1|1].minv += a[mid+1] * tr[rt].lazy;
    		tr[rt].lazy = 0;
    	}
    }
    
    int find(ll v){
    	int rt = 1;
    	int l = 1, r = n;
    	int ans = -1;
    	while(l <= r){
    		push_down(rt, l, r);
    		int mid = l+r>>1;
            if(l==r){
                if(tr[rt].minv > v) ans = l;
                break;
            }
    		if(tr[rt<<1|1].minv > v){
    			ans = mid+1;
    			rt = rt<<1;
    			r = mid;
    		}else{
    			rt = rt<<1|1;
    			l = mid+1;
    		}
    	}
    	return ans;
    }
    
    ll query(int rt, int l, int r, int ql, int qr){
    	if(ql <= l && qr >= r){
    		return tr[rt].sum;
    	}else{
    		push_down(rt, l, r);
    		int mid = l+r>>1;
    		ll ans = 0;
    		if(ql <= mid) ans += query(rt<<1, l, mid, ql, qr);
    		if(qr > mid) ans += query(rt<<1|1, mid+1, r, ql, qr);
    		return ans;
    	}
    }
    
    void cut(int rt, int l, int r, int cl, int cr, ll v){
    	if(cl <= l && cr >= r){
    		tr[rt].sum = v * (r-l+1);
    		tr[rt].minv = v;
    		tr[rt].lazy = 0;
    		tr[rt].setlazy = v;
    		// 置位操作会清楚当前节点的+操作
            // 在pushdown的时候先置位再+
    		// 如果+lazy不为0,说明是先置位再+
    	}else{
    		int mid = l+r>>1;
    		push_down(rt, l, r);
    		if(cl <= mid){
    			cut(rt<<1, l, mid, cl, cr, v);
    		}
    		if(cr > mid){
    			cut(rt<<1|1, mid+1, r, cl, cr, v);
    		}
            push_up(rt);
    	}
    }
    
    int main(){
        // freopen("C:\Users\13234\Desktop\files\IO\0.in","r",stdin);
        // freopen("C:\Users\13234\Desktop\files\IO\0.out","w",stdout);
    	scanf("%d%d", &n, &m);
    	for(int i = 1; i <= n; ++i){
    		scanf("%d", &a[i]);
    	}
        sort(a+1, a+1+n);
    	build(1, 1, n);
    	ll prek = 0;
    	while(m--){
    		scanf("%lld%lld", &k, &v);
    		ll c = k - prek;
    		prek = k;
            push_down(1, 1, n);
    		tr[1].sum += tr[1].inc * c;
    		tr[1].minv += a[1] * c;
    		tr[1].lazy += c;
    		int p = find(v);
    		if(p == -1){
    			printf("0
    ");
    			continue;
    		}
    		ll res = query(1, 1, n, p, n) - (n-p+1) * v;
    		cut(1, 1, n, p, n, v);
    		printf("%lld
    ", res);
    	}
    	return 0;
    }
    
    ---- suffer now and live the rest of your life as a champion ----
  • 相关阅读:
    python time 转换&运算tips
    Web.py session用户认证
    简单的内存池实现gko_alloc
    cpp(第十章)
    cpp(第九章)
    cpp(第八章)
    cpp(第七章)
    cpp(第六章)
    cpp(第五章)
    结构中的位字段
  • 原文地址:https://www.cnblogs.com/popodynasty/p/14631380.html
Copyright © 2011-2022 走看看