CodeForces - 722C_Destroying Array 并查集应用

版权声明:转载请注明出处 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;
}

猜你喜欢

转载自blog.csdn.net/jay__bryant/article/details/81429881