2019 우 객 여름 방학 다 교 훈련소 (4 차 전)C 문제 시퀀스 (선분 트 리 + 단조 창고)

29342 단어 ACM
제목 링크:https://ac.nowcoder.com/acm/contest/884/C
제목: n 길이 의 서열 a, b 두 개 를 드 리 겠 습 니 다. 하위 구간 [l, r] 을 선택 하면 a 서열 이 [l, r] 에서 의 최소 값 곱 하기 b 서열 [l, r] 의 합 을 얻 을 수 있 습 니 다. 이 값 이 가장 큰 것 은 얼마 입 니까?
생각:
  • 우선, 우 리 는 현재 이 숫자 로 a [i] 를 기록 합 니 다. 그것 은 그 구간 에서 가장 작은 값 입 니 다. L [i], R [i]
  • 그리고 우 리 는 선분 트 리 로 접두사 와
  • 를 유지 합 니 다.
  • a [i] 가 0 보다 크 면 최대 치 는 이 수 a [i] 곱 하기 와 가장 큰 구간 (즉, [i, R [i] 에서 접두사 와 최대 치 - [L [i], i - 1] 에서 접두사 와 최소 치)
  • a [i] 가 0 보다 작 을 때 값 을 최대 로 해 야 합 니 다. 구간 값 이 가장 작 더 라 도 a [i] 곱 하기 ([i, R [i] 에서 접두사 와 최소 값 - [L [i], i - 1] 에서 접두사 와 최대 값)


  • 참고 블 로그
  • https://www.cnblogs.com/wuliking/p/11261576.html
  • https://blog.csdn.net/anthony1314/article/details/97535853

  • 코드
    #include 
    using namespace std;
    const int MAXN = 3000005;
    long long node[2][MAXN<<2];
    long long per[MAXN];
    long long a[MAXN], b[MAXN];
    int l[MAXN], r[MAXN];
    //    
    inline void PushUp(int root)
    {
        //    
        node[0][root] = max(node[0][root<<1], node[0][root<<1|1]);
        node[1][root] = min(node[1][root<<1], node[1][root<<1|1]);
    }
    //1.  
    inline void BuildTree(int root, int l, int r)     //[l,r]       , root        
    {
        if(l == r){
            //            
            node[0][root] = node[1][root] = per[l];    //      
            return ;
        }
        int mid = (l + r) >> 1;
        //      
        BuildTree(root<<1, l, mid);// 
        BuildTree(root<<1|1, mid + 1, r);// 
    
        //    (       )
        PushUp(root);
    
    }
    //    
    inline long long QueryMax(int root, int l, int r, int L, int R)
    {
        // root        , [l,r]      , [L,R]          
        if(L <= l && r <= R){
            //          ,        
            return node[0][root];
        }
        int mid = (l + r) >> 1;
    
        long long ans = -1e18;
        if(L <= mid)
            ans = max(QueryMax(root<<1, l, mid, L, R), ans);
        if(R > mid)
            ans = max(QueryMax(root<<1|1, mid + 1, r, L, R), ans);
    
        return ans;
    }
    //    
    inline long long QueryMin(int root, int l, int r, int L, int R)
    {
        // root        , [l,r]      , [L,R]          
        if(L <= l && r <= R){
            //          ,        
            return node[1][root];
        }
        int mid = (l + r) >> 1;
    
        long long ans = 1e18;
    
        if(L <= mid)
            ans = min(QueryMin(root<<1, l, mid, L, R), ans);
        if(R > mid)
            ans = min(QueryMin(root<<1|1, mid + 1, r, L, R), ans);
    
        return ans;
    }
    int main()
    {
        ios::sync_with_stdio(false);
        int n;
        cin >> n;
        for(int i = 1; i <= n; i++) cin >> a[i];
        per[0] = 0;
        for(int i = 1; i <= n; i++){
            cin >> b[i];
            per[i] = per[i - 1] + b[i];
        }
        //      [0, n]         per[1] - per[0]
        BuildTree(1, 0, n);
        stack<int> st;
        //  L[i]
        for(int i = 1; i <= n; i++){
            while(st.size() && a[st.top()] >= a[i]) st.pop();
    
            if(st.size() == 0) l[i] = 0;
            else l[i] = st.top();
    
            st.push(i);
        }
    
        while(st.size()) st.pop();
    
        //  R[i]
        for(int i = n; i >= 1; i--){
            while(st.size() && a[st.top()] >= a[i]) st.pop();
            if(st.size() == 0) r[i] = n;
            else r[i] = st.top() - 1;
            st.push(i);
        }
    
        long long ans = -1e18;
    
        for(int i = 1; i <= n; i++){
            if(a[i] >= 0){
                ans = max(ans, (QueryMax(1, 0, n, i, r[i]) - QueryMin(1, 0, n, l[i], i - 1)) * a[i]);
            }
            else{
                ans = max(ans, (QueryMin(1, 0, n, i, r[i]) - QueryMax(1, 0, n, l[i], i - 1)) * a[i]);
            }
        }
    
        cout << ans << endl;
    
        return 0;
    }
    

    좋은 웹페이지 즐겨찾기