版权声明:转载请注明出处 https://blog.csdn.net/jay__bryant/article/details/81429881
题目大意:给定数组大小n,再给定数组元素(从1~n编号),最后给定数组元素的删除顺序,求执行完每一次删除操作后,数组的最大连续子段和。
倒着处理,并查集。
(1)初始化数组为空,倒着加入元素。
(2)每一次加入元素,如果其左右两边也加入过了,就与左或者右边并在一起得到新的数值。当前答案来源于上一次的答案或者本次更新的数值,将两者取最大值即可。
//并查集,倒着处理
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1e5+10;
ll a[N], ans[N], son[N];
int b[N], fa[N];
bool vis[N];
int findf(int x)
{
return x==fa[x]?x:fa[x]=findf(fa[x]);
}
void merge_(int x, int y)
{
int f1 = findf(x);
int f2 = findf(y);
if(f1 != f2)
{
fa[f2] = f1;
son[f1] += son[f2];
}
}
int main()
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
for(int i = 1; i <= n; ++i) scanf("%d", &b[i]);
for(int i = 1; i <= n; ++i) fa[i] = i, son[i] = a[i];
memset(vis, 0, sizeof(vis));
ans[n] = 0;
for(int i = n; i > 1; --i)
{
int pos = b[i];
vis[pos] = 1;
if(vis[pos-1]) merge_(pos-1, pos);
if(vis[pos+1]) merge_(pos+1, pos);
ans[i-1] = max(ans[i], son[findf(pos)]);
}
for(int i = 1; i <= n; ++i) printf("%lld\n", ans[i]);
return 0;
}