摧毁数组
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]);
}