51nod_2607 摧毁数组(并查集)

摧毁数组

Problem Description

有一个由n个非负整数组成的数列 a1,a2,a3…an。现在将要一个一个摧毁这个数列中的数。同时,有一个由 1 到 n 组成的序列来告诉你每个数被摧毁的时间顺序。

每当一个元素被摧毁时,你需要找到这个当前数列中的未被摧毁的数组成的和最大的连续子序列,另外,如果当前剩余的序列是空的的话,最大和就是0。

第一个样例:

1.第三个数被删除了,现在的数列是 1 3 O 5 ,答案为5由一个数5组成。

2.第四个数被删除了,现在的数列是 1 3 O O ,答案为4由两个数1和3组成。

3.第一个数被删除了,现在的数列是 O 3 O O ,答案为3由一个数3组成。

4.第二个数被删除了,现在的数列是O O O O,答案为0没有数字组成。

Input

第一行包含一个整数n (1 <= n <= 100000) , 代表数列的长度。
第二行包含n个整数 ,第i个数为a[i].0<=a[i]<=1000000000。
第三行包含一个由1到n的整数组成的序列,代表数被摧毁的顺序。

Output

输出有n行,第i行包含一个整数表示在第i个操作已经执行完之后,数列中连续的最大和。

Sample Input

4
1 3 2 5
3 4 1 2

Sample Output

5
4
3
0

题解:

因为a[i]>=0,所以最大的和一定是被分割开的若干个子段中的一个。倒着处理删除操作,从最后一个开始,向数组内加元素,如果它左右或右边的已经被加入,则合并区间,并查集维护即可。

#include<stdio.h>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
#include<vector>
#include<queue>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-7
 
using namespace std;
typedef long long LL;   
typedef pair<int, int> P;
const int maxn = 100100;
const int mod = 998244353;
int a[maxn], b[maxn], c[maxn], vis[maxn];
LL maxx, ans[maxn], mx[maxn];
int Find(int x);

int main()
{
    int n, i, j, k;
    scanf("%d", &n);
    for(i=1;i<=n;i++)
        a[i] = i, mx[i] = 0LL;
    for(i=1;i<=n;i++)
        scanf("%d", &b[i]);
    for(i=1;i<=n;i++)
        scanf("%d", &c[i]);
    for(i=n;i>=1;i--){
        vis[c[i]] = 1, mx[c[i]] = b[c[i]];
        int x = Find(c[i]);
        if(vis[c[i]+1]){
            int y = Find(c[i]+1);
            a[y] = x;
            mx[x] = mx[y]+mx[x];
        }
        if(vis[c[i]-1]){
            int y = Find(c[i]-1);
            a[y] = x;
            mx[x] = mx[y]+mx[x];
        }
        ans[i] = maxx;
        maxx = max(maxx, mx[x]);
    }
    for(i=1;i<=n;i++)
        printf("%lld\n", ans[i]);
    return 0;
}

int Find(int x)
{
    return a[x]=x==a[x]?x:Find(a[x]);
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值