Intel Code Challenge Elimination Round (Div.1 + Div.2, combined) C. Destroying Array 双向链表+反向做+优先队列

C. Destroying Array
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given an array consisting of n non-negative integers a1, a2, ..., an.

You are going to destroy integers in the array one by one. Thus, you are given the permutation of integers from 1 to n defining the order elements of the array are destroyed.

After each element is destroyed you have to find out the segment of the array, such that it contains no destroyed elements and the sum of its elements is maximum possible. The sum of elements in the empty segment is considered to be 0.

Input

The first line of the input contains a single integer n (1 ≤ n ≤ 100 000) — the length of the array.

The second line contains n integers a1, a2, ..., an (0 ≤ ai ≤ 109).

The third line contains a permutation of integers from 1 to n — the order used to destroy elements.

Output

Print n lines. The i-th line should contain a single integer — the maximum possible sum of elements on the segment containing no destroyed elements, after first i operations are performed.

Examples
input
4
1 3 2 5
3 4 1 2
output
5
4
3
0
input
5
1 2 3 4 5
4 2 3 5 1
output
6
5
5
1
0
input
8
5 5 4 4 6 6 5 5
5 2 8 7 1 3 4 6
output
18
16
11
8
8
6
6
0
Note

Consider the first sample:

  1. Third element is destroyed. Array is now 1 3  *  5. Segment with maximum sum 5 consists of one integer 5.
  2. Fourth element is destroyed. Array is now 1 3  *   * . Segment with maximum sum 4 consists of two integers 1 3.
  3. First element is destroyed. Array is now  *  3  *   * . Segment with maximum sum 3 consists of one integer 3.
  4. Last element is destroyed. At this moment there are no valid nonempty segments left in this array, so the answer is equal to 0.


Source

Intel Code Challenge Elimination Round (Div.1 + Div.2, combined)


My Solution

 双向链表+反向做+优先队列

反向做,按着反的顺序把元素一个一个的添加进去,用priority_queue 维护当前最值,

用双向链表维护当前区间的状态,L[i]表示以i为端点的区间的区间左端点,R[i]表示以i为区间端点的右端点

对于每个点 j, 当只R[i + 1] != 0 时, 右边有区间,可以把两个链表合并成一个, R[i] = R[i + 1], L[i]  = i;

                           当只L[i - 1] != 0 时, 左边有区间,可以把两个链表合并成一个, R[L[i - 1]] = i, R[i] = i, L[i] = L[i - 1]

   当两边都有区间时,先合并一边,再合并另一边最后得到的区间是 [ L[i - 1], R[i + 1] ];

然后根据合并来的区间得到新的区间和,push到priority_queue里,这个和必定比原来分开的子区间大,所以原来的子区间和就留在pq里不用管了。最多维护n个元素

区间和用 map<pair<int, int>, LL> mp,来维护, mp[ii(i, i)] = a[per[i]];, 然后 mp[ii(l, r)]就用来维护新的区间的和,然后push到pq里。

复杂度 O(nlogn)


#include <iostream>
#include <cstdio>
#include <queue>
#include <map>
#include <cstring>
using namespace std;
typedef long long LL;
typedef pair<int, int> ii;
const int maxn = 1e5 + 8;

priority_queue<LL> pq;
map<ii, LL> mp;

LL a[maxn], per[maxn], L[maxn], R[maxn], ans[maxn];

int main()
{
    #ifdef LOCAL
    freopen("c.txt", "r", stdin);
    //freopen("c.out", "w", stdout);
    int T = 3;
    while(T--){
    #endif // LOCAL
    ios::sync_with_stdio(false); cin.tie(0);

    LL n, l, r, sum;
    cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> a[i];
    }
    for(int i = 1; i <= n; i++){
        cin >> per[i];
    }

    for(int i = n; i > 0; i--){
        if(i == n){
            L[per[n]] = per[n];
            R[per[n]] = per[n];
            mp[ii(per[n], per[n])] = a[per[n]];
            pq.push(a[per[n]]);
            ans[n] = 0;
        }
        else{
            ans[i] = pq.top();
            sum = a[per[i]];
            l = per[i], r = per[i];
            L[l] = l, R[l] = l;
            if(L[per[i]+1] != 0){
                L[per[i]] = per[i];
                R[per[i]] = R[per[i]+1];
                L[R[per[i]+1]] = per[i];
                r = R[per[i]];
                sum += mp[ii(per[i]+1, r)];
            }
            if(R[per[i]-1] != 0){
                if(R[per[i]] != 0){
                    R[L[per[i]-1]] = R[per[i]];
                    L[R[per[i]]] = L[per[i]-1];
                    l = L[per[i]-1];
                    sum += mp[ii(l, per[i]-1)];

                }
                else{
                    R[L[per[i]-1]] = per[i];
                    R[per[i]] = per[i];
                    L[per[i]] = L[per[i]-1];
                    l = L[per[i]-1];
                    sum += mp[ii(l, per[i]-1)];
                }

            }
            mp[ii(l, r)] = sum;
            pq.push(sum);
        }
    }

    for(int i = 1; i <= n; i++){
        cout << ans[i] << "\n";
    }
    #ifdef LOCAL
    memset(L, 0, sizeof L);
    memset(R, 0, sizeof R);
    mp.clear();
    while(!pq.empty()) pq.pop();
    cout << endl;
    }
    #endif // LOCAL
    return 0;
}

  Thank you!

                                                                                                                                               ------from ProLights 

你可能感兴趣的:(双向链表,ACM,优先队列,codeforces,反向做)