• Petrozavodsk Summer Training Camp 2016H(多标记线段树)题解


    题意:

    (n)个草,第(0)天种下,高度都为(0),每个草每天长高(a_i)。现给出(q)询问,每次给出第(b_i)天,然后把高于(d_i)的全削成(d_i),每次问你此次削下来的高度是多少,(b_{i-1}<b_i)

    思路:

    能看出草的顺序和答案无关,那么按(a_i)排序,后面的草永远都比前面的高。然后线段树维护区间加,区间重置,区间询问。

    代码:

    #include<set>
    #include<map>
    #include<cmath>
    #include<queue>
    #include<bitset>
    #include<string>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include <iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 5e5 + 5;
    const int M = 50 + 5;
    const ull seed = 131;
    const int INF = 0x3f3f3f3f;
    const ll MOD = 1000000007;
    
    #define lson (rt << 1)
    #define rson (rt << 1 | 1)
    int n, m;
    ll sum[maxn << 2], sumW[maxn << 2], Mw[maxn << 2], Max[maxn << 2];
    ll t[maxn << 2], reset[maxn << 2];
    //时间戳,重置
    ll a[maxn];
    void pushup(int rt){
        sum[rt] = sum[lson] + sum[rson];
        Max[rt] = Max[rson];
        Mw[rt] = Mw[rson];
        sumW[rt] = sumW[lson] + sumW[rson];
    }
    void pushdown(int rt, int l, int r){
        int m = (l + r) >> 1;
        if(reset[rt] != -1){
            reset[lson] = reset[rt];
            reset[rson] = reset[rt];
            t[lson] = 0;
            t[rson] = 0;
            Max[lson] = reset[rt];
            Max[rson] = reset[rt];
            sum[lson] = 1LL * reset[rt] * (m - l + 1);
            sum[rson] = 1LL * reset[rt] * (r - m);
            reset[rt] = -1;
        }
        if(t[rt]){
            sum[lson] += t[rt] * sumW[lson];
            sum[rson] += t[rt] * sumW[rson];
            Max[lson] += t[rt] * Mw[lson];
            Max[rson] += t[rt] * Mw[rson];
            t[lson] += t[rt];
            t[rson] += t[rt];
            t[rt] = 0;
        }
    }
    void build(int l, int r, int rt){
        t[rt] = 0;
        reset[rt] = -1;
        if(l == r){
            sumW[rt] = Mw[rt] = a[l];
            sum[rt] = Max[rt] = 0;
            return;
        }
        int m = (l + r) >> 1;
        build(l, m, lson);
        build(m + 1, r, rson);
        pushup(rt);
    }
    void _set(int L, int R, int l, int r, ll v, int rt){
        if(L <= l && R >= r){
            sum[rt] = 1LL * v * (r - l + 1);
            reset[rt] = v;
            Max[rt] = v;
            t[rt] = 0;
            return;
        }
        pushdown(rt, l, r);
        int m = (l + r) >> 1;
        if(L <= m)
            _set(L, R, l, m, v, lson);
        if(R > m)
            _set(L, R, m + 1, r, v, rson);
        pushup(rt);
    }
    void add(int L, int R, int l, int r, ll v, int rt){
        if(L <= l && R >= r){
            sum[rt] += sumW[rt] * v;
            t[rt] += v;
            Max[rt] += Mw[rt] * v;
            return;
        }
        pushdown(rt, l, r);
        int m = (l + r) >> 1;
        if(L <= m)
            add(L, R, l, m, v, lson);
        if(R > m)
            add(L, R, m + 1, r, v, rson);
        pushup(rt);
    }
    ll querysum(int L, int R, int l, int r, int rt){
        if(L <= l && R >= r){
            return sum[rt];
        }
        pushdown(rt, l, r);
        int m = (l + r) >> 1;
        ll ret = 0;
        if(L <= m)
            ret += querysum(L, R, l, m, lson);
        if(R > m)
            ret += querysum(L, R, m + 1, r, rson);
        return ret;
    }
    int queryMore(int l, int r, ll v, int rt){
        if(l == r){
            return Max[rt] > v? l : -1;
        }
        pushdown(rt, l, r);
        int m = (l + r) >> 1;
        if(Max[lson] > v)
            return queryMore(l, m, v, lson);
        else
            return queryMore(m + 1, r, v, rson);
    }
    int main(){
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
        sort(a + 1, a + n + 1);
        build(1, n, 1);
        ll u, v, pre = 0;
        while(m--){
            scanf("%lld%lld", &u, &v);
            add(1, n, 1, n, u - pre, 1);
            int pos = queryMore(1, n, v, 1);
            if(pos == -1) puts("0");
            else{
                ll ret = querysum(pos, n, 1, n, 1);
                ret = ret - 1LL * v * (n - pos + 1);
                printf("%lld
    ", ret);
                _set(pos, n, 1, n, v, 1);
            }
            pre = u;
        }
        return 0;
    }
    
    
  • 相关阅读:
    Android面试题
    java面试题大全
    关于索引的sql语句优化之降龙十八掌
    java动态代理的实现
    java动态代理
    进程与线程
    SqlServer聚合函数
    2015年创业中遇到的技术问题:21-30
    hadoop集群ambari搭建(2)之制作hadoop本地源
    Android录屏命令、Android录Gif、Android录视频
  • 原文地址:https://www.cnblogs.com/KirinSB/p/11618662.html
Copyright © 2020-2023  润新知