Destroying Array CF 722C

题目大意就是给长度为 n 一个数列,有 n 每次删除,每一次删除第 i 个位置上的数,求每一次删除后剩余不连续数列的最大区间和。

输入样例

4

1 3 2 5

3 4 1 2

输出样例

5

4

3

0

第二行是原来的数列,第三行是删除第 i 个数。

 

这道题的正解是用并查集来做。要将删除的顺序存下来,并倒序操作,这样就相当于每一次加上第 i 数。然后判断加上的数的左右两边是否有数,有就合并,并尝试用合并的新的区间和更新答案。对了,答案也要存下来,再倒序输出,才是真正的答案。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cmath>
 5 using namespace std;
 6 typedef long long ll;
 7 const int maxn = 1e5 + 5;
 8 ll a[maxn], b[maxn], sum[maxn], ans[maxn], maxm = -1;
 9 int p[maxn], n; 
10 bool vis[maxn];        //vis[i]判断第i个位置上的数是否存在 
11 void init()            //并查集初始化:每一个点都是自己的父亲节点 
12 {
13     for(int i  = 0; i < maxn; ++i) {sum[i] = 0; p[i] = i;}
14     return;
15 }
16 int Find(int x)
17 {
18     return p[x] == x ? x : p[x] = Find(p[x]);
19 }
20 void merge(int x, int y)        //合并 
21 {
22     int px = Find(x), py = Find(y);
23     //肯定不联通
24     p[px] = py;
25     sum[py] += sum[px];
26     return; 
27 }
28 int main()
29 {
30     init();
31     scanf("%d", &n);
32     for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
33     for(int i = 1; i <= n; ++i) scanf("%lld", &b[i]);
34     for(int i = n; i > 0; --i)
35     {
36         vis[b[i]] = 1;
37         sum[b[i]] = a[b[i]];
38         if(vis[b[i] - 1]) merge(b[i], b[i] - 1);    //左边是否有数 
39         if(vis[b[i] + 1]) merge(b[i], b[i] + 1);    //右边是否有数 
40         if(sum[Find(b[i])] > maxm) maxm = sum[Find(b[i])];    //尝试更新最大区间和 
41         ans[i - 1] = maxm;
42     }
43     for(int i = 1; i <= n; ++i) printf("%lld\n", ans[i]);
44     return 0;
45 }

 

 


posted @ 2018-02-22 16:56  mrclr  阅读(239)  评论(0编辑  收藏  举报