題目大意:給定數組大小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;
}