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.
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.
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.
4 1 3 2 5 3 4 1 2
5 4 3 0
5 1 2 3 4 5 4 2 3 5 1
6 5 5 1 0
8 5 5 4 4 6 6 5 5 5 2 8 7 1 3 4 6
18 16 11 8 8 6 6 0
Consider the first sample:
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