Cod sursa(job #2054834)

Utilizator mlc_oficialBoris Barca mlc_oficial Data 2 noiembrie 2017 16:32:44
Problema SequenceQuery Scor 100
Compilator cpp Status done
Runda Arhiva de probleme Marime 7.28 kb
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,popcnt,abm,mmx,tune=native")
#include <cassert>
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <memory>

using namespace std;

constexpr int64_t inf = 1e18;

struct LeafValue {
    int x; 
    LeafValue(const int _x = 0) : x(_x) { }
};

struct NodeValue {
    int64_t mx_sum, mx_prefix, mx_suffix, sum;
    NodeValue() : mx_sum(-inf), mx_prefix(-inf), mx_suffix(-inf), sum(0) { }
    NodeValue(const LeafValue& value, const int pos) : mx_sum(value.x), mx_prefix(value.x), mx_suffix(value.x), sum(value.x) {
    } 
    
    NodeValue& operator +=(const NodeValue& rhs) {
        mx_sum = max({mx_sum, mx_suffix + rhs.mx_prefix, rhs.mx_sum});
        mx_prefix = max(mx_prefix, sum + rhs.mx_prefix);
        mx_suffix = max(mx_suffix + rhs.sum, rhs.mx_suffix);
        mx_sum = max({mx_sum, mx_prefix, mx_suffix});
        sum += rhs.sum;
        return *this;
    }
    NodeValue operator +(const NodeValue& rhs) const {
        return NodeValue(*this) += rhs;
    }
};

struct LazyValue {
    int delta;
    LazyValue() : delta(0) { }
    LazyValue& operator +=(const LazyValue& rhs) {
        delta += rhs.delta;
        return *this;
    } 
    
    void AddToLeaf(LeafValue& value, int pos) const {
        //value.x += delta;
    }
    
    void AddToNode(NodeValue& value, int left, int right) const {
        //value.mx += delta;
    }
};

class LazySegmentTree {
public:
    LazySegmentTree(int n, const LeafValue& v = LeafValue()) { Init(vector<LeafValue>(n, v)); }
    LazySegmentTree(const vector<LeafValue>& v) { Init(v); }
    
    LeafValue Get(int pos) {
        Propagate(FindIdx(pos, pos + 1));
        return leaves[pos];
    }
    
    NodeValue GetRangeCommutative(int left, int right) {
        Propagate(FindIdx(left, right));
        
        NodeValue answer = NodeValue();
        left += tree_size; right += tree_size;
        while (left < right) {
            if (left % 2) {
                answer += FindNodeValue(left++);
            }
            if (right % 2) {
                answer += FindNodeValue(--right);
            }
            left /= 2; right /= 2;
        }
        return answer;
    }
    
    NodeValue GetRange(int left, int right) {
        Propagate(FindIdx(left, right));
        
        NodeValue answer = NodeValue();
        while (left > 0 and left + lsb(left) <= right) {
            answer += FindNodeValue((tree_size + left) / lsb(left));
            left += lsb(left);
        }
        
        int num_idx = 0;
        while (right > left) {
            idx[num_idx++] = (tree_size + right) / lsb(right) - 1;
            right -= lsb(right);
        }
        while (num_idx--) {
            answer += FindNodeValue(idx[num_idx]);
        }
        return answer;
    }
    
    void Set(int pos, const LeafValue& value) {
        const int n = FindIdx(pos, pos + 1);
        Propagate(n);
        leaves[pos] = value;
        Merge(n);
    }
    
    void AddRange(int left, int right, const LazyValue& add) {
        if (left >= right) {
            return;
        }
        
        const int n = FindIdx(left, right);
        Propagate(n);
        left += tree_size; right += tree_size;
        if (left % 2) {
            add.AddToLeaf(leaves[left - tree_size], left - tree_size);
            left += 1;
        }
        if (right % 2) {
            right -= 1;
            add.AddToLeaf(leaves[right - tree_size], right - tree_size);
        }
        
        left /= 2; right /= 2;
        while (left < right) {
            if (left % 2) {
                delta[left++] += add;
            }
            if (right % 2) {
                delta[--right] += add;
            }
            left /= 2; right /= 2;
        }
        Merge(n);
    }
private:
    static inline int lsb(int value) {
        return value & -value;
    }
    
    void Init(const vector<LeafValue>& v) {
        int n = static_cast<int>(v.size());
        tree_size = 1;
        while (tree_size < n) {
            tree_size *= 2;
        }
        
        leaves = v;
        leaves.resize(tree_size);
        nodes.resize(tree_size);
        for (int i = tree_size - 1; i >= (tree_size / 2); i -= 1) {
            nodes[i] = NodeValue(leaves[(2 * i) - tree_size], (2 * i) - tree_size)
                     + NodeValue(leaves[(2*i+1) - tree_size], (2*i+1) - tree_size);
        }
        for (int i = (tree_size / 2) - 1; i > 0; i -= 1) {
            nodes[i] = nodes[2 * i] + nodes[2 * i + 1];
        }
        delta.assign(tree_size, LazyValue());
        
        idx_left.resize(tree_size);
        idx_right.resize(tree_size);
        for (int i = tree_size - 1; i >= (tree_size / 2); i -= 1) {
            idx_left[i] = (2 * i) - tree_size;
            idx_right[i]= (2*i+1) - tree_size;
        }
        for (int i = (tree_size / 2) - 1; i > 0; i -= 1) {
            idx_left[i] = idx_left[2 * i];
            idx_right[i]=idx_right[2*i+1];
        }
        idx = unique_ptr<int[]>(new int[128]);
    }
    
    NodeValue FindNodeValue(int node) {
        PropagateAt(node);
        return node < tree_size ? nodes[node] : 
                NodeValue(leaves[node - tree_size], node - tree_size);
    }
    
    int FindIdx(int left, int right) {
        if (left >= right) {
            return 0;
        }
        
        int num_idx = 0;
        left = (left + tree_size) / 2;
        right = (right + tree_size - 1) / 2;
        while (left != right) {
            idx[num_idx + 0] = left;
            idx[num_idx + 1] = right;
            num_idx += 2;
            left /= 2; right /= 2;
        }
        while (left > 0) {
            idx[num_idx++] = left;
            left /= 2;
        }
        return num_idx;
    } 
    
    void Propagate(int num_idx) {
        while (num_idx--) {
            PropagateAt(idx[num_idx]);
        }
    }
    
    void PropagateAt(int node) {
        if (node >= tree_size) {
            return;
        }
        
        delta[node].AddToNode(nodes[node], idx_left[node], idx_right[node]);
        if (2 * node < tree_size) {
            delta[2 * node] += delta[node];
            delta[2*node+1] += delta[node];
        } else {
            delta[node].AddToLeaf(leaves[(2 * node) - tree_size], (2 * node) - tree_size);
            delta[node].AddToLeaf(leaves[(2*node+1) - tree_size], (2*node+1) - tree_size);
        }
        delta[node] = LazyValue();
    }
    
    void Merge(int num_idx) {
        for (int i = 0; i < num_idx; i += 1) {
            MergeAt(idx[i]);
        }    
    }
    
    void MergeAt(int node) {
        if (node < tree_size) {
            nodes[node] = FindNodeValue(2 * node) + FindNodeValue(2 * node + 1);
        }
    }
    
    vector<LeafValue> leaves;
    vector<NodeValue> nodes;
    vector<LazyValue> delta;
    vector<int> idx_left, idx_right;
    unique_ptr<int[]> idx;
    int tree_size;
};

int main() {
    #ifdef INFOARENA
    ifstream cin("sequencequery.in");
    ofstream cout("sequencequery.out");
    #endif
    cin.tie(0);
    ios_base::sync_with_stdio(false);
    
    int n, q; cin >> n >> q;
    vector<LeafValue> v(n);
    for (auto& el : v) {
        cin >> el.x;
    }
    
    LazySegmentTree tree(v);
    while (q--> 0) {
        int left, right; cin >> left >> right; left -= 1; right -= 1;
        cout << tree.GetRange(left, right + 1).mx_sum << '\n';
    }
    return 0;
}