题目大意就是给长度为 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 ", ans[i]); 44 return 0; 45 }