题干:
给定一个有n个数的序列a1,a2, ..., an
你每次可以将序列中一个数删去,剩下的数会被分割为一段一段连续的数列
给定一个删除数的顺序,问在每次删除之后,剩下的连续的数列中,数列和的最大值为多少
Input
第一行输入仅有一个正整数n(1<=n<=100000)
第二行包括n个整数a1,a2, ..., an(0<=ai<=1,000,000,000)
第三行为n个正整数的一个全排列,为删除元素的顺序。
Examples
Input
4
1 3 2 5
3 4 1 2
Output
5
4
3
0
Input
5
1 2 3 4 5
4 2 3 5 1
Output
6
5
5
1
0
Input
8
5 5 4 4 6 6 5 5
5 2 8 7 1 3 4 6
Output
18
16
11
8
8
6
6
0
Note
Consider the first sample:
- Third element is destroyed. Array is now 1 3 * 5. Segment with maximum sum 5consists of one integer 5.
- Fourth element is destroyed. Array is now 1 3 * * . Segment with maximum sum 4consists of two integers 1 3.
- First element is destroyed. Array is now * 3 * * . Segment with maximum sum 3consists of one integer 3.
- Last element is destroyed. At this moment there are no valid nonempty segments left in this array, so the answer is equal to 0.
解题报告:
倒着考虑操作,并查集维护最大值即可。具体就是如果当前操作位置idx,如果左边已经操作过,那就可以想做合并,同理可以向右合并,注意a[i]可以为0,所以不能用sum数组来判断是否出现过,而应该新开一个数组ok来记录。
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define FF first
#define SS second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
int n,op[MAX],f[MAX];
ll a[MAX],sum[MAX],ans[MAX],mx;
int getf(int v) {return f[v] == v ? v : f[v] = getf(f[v]);
}
void merge(int u,int v) {int t1 = getf(u),t2 = getf(v);if(t1 == t2) return;f[t2] = t1;sum[t1] += sum[t2];mx = max(mx,sum[t1]);
}
bool ok[MAX];
int main()
{cin>>n;for(int i = 1; i<=n; i++) scanf("%lld",a+i),f[i] = i;for(int i = 1; i<=n; i++) scanf("%d",op+i);for(int i = n; i>=1; i--) {sum[op[i]] = a[op[i]];ok[op[i]]=1;mx = max(mx,sum[op[i]]);if(ok[op[i]+1] != 0) merge(op[i],op[i]+1);if(ok[op[i]-1] != 0) merge(op[i],op[i]-1);ans[i]=mx;}for(int i = 2; i<=n; i++) printf("%lld\n",ans[i]);puts("0");return 0 ;
}