Intel Code Challenge Elimination Round (Div.1 + Div.2, combined)C. Destroying Array(想法题/并查集)
Description
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.
Sample Input
4
1 3 2 5
3 4 1 2
5
1 2 3 4 5
4 2 3 5 1
8
5 5 4 4 6 6 5 5
5 2 8 7 1 3 4 6
Sample Output
5
4
3
0
6
5
5
1
0
18
16
11
8
8
6
6
0
Note
Consider the first sample:
- Third element is destroyed. Array is now 1 3 * 5. Segment with maximum sum 5 consists of one integer 5.
- Fourth element is destroyed. Array is now 1 3 * * . Segment with maximum sum 4 consists of two integers 1 3.
- First element is destroyed. Array is now * 3 * * . Segment with maximum sum 3 consists of one integer 3.
- Last element is destroyed. At this moment there are no valid nonempty segments left in this array, so the answer is equal to 0.
思路
题意:
给定一个长度为n的数字序列,每次删除一个数,问剩下的段中和最大的值为多少
题解:
使用multiset存下每次删除的位置,以及每段的和,利用预处理的前缀和,依次更新就好了。注意:multiset容器中有多个相同值的时候,使用erase函数会把所有相同的值都删除,如果只是想删除一个数,那么可以用s.erase(s.find(val))来删除一个值为val的数。 另外,本题也可以倒着做,看作是初始一个数都没有,然后将数一个个放到指定的位置,那么就可以利用并查集,使放在相邻的数为一个集合,更新每个集合的和,求得最大值。
#include<bits/stdc++.h> using namespace std; typedef __int64 LL; const int maxn = 100005; LL a[maxn],sum[maxn]; multiset<int>pos; multiset<LL>s; multiset<int>::iterator front,rear; multiset<LL>::iterator it; int main() { int n,p; scanf("%d",&n); for (int i = 0;i < n;i++) { scanf("%I64d",&a[i]); sum[i+1] = sum[i] + a[i]; } sum[n+1] = sum[n]; pos.insert(0),pos.insert(n+1); s.insert(sum[n]); while (n--) { scanf("%d",&p); pos.insert(p); front = rear = pos.find(p); front--,rear++; s.erase(s.find(sum[*rear-1]-sum[*front])); s.insert(sum[*rear-1]-sum[p]); s.insert(sum[p-1]-sum[*front]); it = s.end(); --it--; cout << *it << endl; } return 0; }
#include<bits/stdc++.h> using namespace std; typedef __int64 LL; const int maxn = 100005; LL sum[maxn],ans[maxn]; int fa[maxn],pos[maxn]; bool vis[maxn]; void init(int n) { memset(vis,false,sizeof(vis)); for (int i = 0;i <= n;i++) fa[i] = i; } int find(int x) { return x == fa[x]?fa[x]:find(fa[x]); } void Union(int x,int y) { int fx = find(x); int fy = find(y); if (fx == fy) return; fa[fx] = fy; sum[fy] += sum[fx]; } int main() { int n; LL tmp = 0; scanf("%d",&n); init(n); for (int i = 1;i <= n;i++) scanf("%I64d",&sum[i]); for (int i = 1;i <= n;i++) scanf("%d",&pos[i]); for (int i = n; i > 0;i--) { ans[i] = tmp; vis[pos[i]] = true; if (pos[i] < n && vis[pos[i] + 1]) Union(pos[i],pos[i]+1); if (pos[i] > 1 && vis[pos[i] - 1]) Union(pos[i],pos[i]-1); tmp = max(tmp,sum[find(pos[i])]); } for (int i = 1;i <= n;i++) printf("%I64d\n",ans[i]); return 0; }
┆ 凉 ┆ 暖 ┆ 降 ┆ 等 ┆ 幸 ┆ 我 ┆ 我 ┆ 里 ┆ 将 ┆ ┆ 可 ┆ 有 ┆ 谦 ┆ 戮 ┆ 那 ┆ ┆ 大 ┆ ┆ 始 ┆ 然 ┆
┆ 薄 ┆ 一 ┆ 临 ┆ 你 ┆ 的 ┆ 还 ┆ 没 ┆ ┆ 来 ┆ ┆ 是 ┆ 来 ┆ 逊 ┆ 没 ┆ 些 ┆ ┆ 雁 ┆ ┆ 终 ┆ 而 ┆
┆ ┆ 暖 ┆ ┆ 如 ┆ 地 ┆ 站 ┆ 有 ┆ ┆ 也 ┆ ┆ 我 ┆ ┆ 的 ┆ 有 ┆ 精 ┆ ┆ 也 ┆ ┆ 没 ┆ 你 ┆
┆ ┆ 这 ┆ ┆ 试 ┆ 方 ┆ 在 ┆ 逃 ┆ ┆ 会 ┆ ┆ 在 ┆ ┆ 清 ┆ 来 ┆ 准 ┆ ┆ 没 ┆ ┆ 有 ┆ 没 ┆
┆ ┆ 生 ┆ ┆ 探 ┆ ┆ 最 ┆ 避 ┆ ┆ 在 ┆ ┆ 这 ┆ ┆ 晨 ┆ ┆ 的 ┆ ┆ 有 ┆ ┆ 来 ┆ 有 ┆
┆ ┆ 之 ┆ ┆ 般 ┆ ┆ 不 ┆ ┆ ┆ 这 ┆ ┆ 里 ┆ ┆ 没 ┆ ┆ 杀 ┆ ┆ 来 ┆ ┆ ┆ 来 ┆