大体题意:
给你n 个数字,告诉你破坏每个数字的顺序,每次破坏后你要求一个线段,使得线段不包含破坏的点,并且线段上的值和最大?
思路:
正着删除感觉不好处理,就反过来求了,相当于从一个空序列往上面添加数值,加一次,求一次线段的最大和,在加之前,我们可以先定义一个变量Max 表示之前的操作所得到的最大线段和,然后和加入后进行比较!
加入某个值后,用了并查集进行处理,令c[i]是 i 这个点的权值,那么先判断i+1的位置,如果有值的话,就把i+1这一系列线段加到i位置上,在判断i-1位置,相当于把位置向小位置上并!
有个坑,自己没有注意到,求和时会爆int,开long long
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 10;
typedef long long ll;
vector<ll>ans;
int a[maxn];
int fa[maxn];
int ord[maxn];
int b[maxn];
ll c[maxn];
int find(int x){
return fa[x] == x ? x : fa[x] = find(fa[x]);
}
void add(int x,int y){
if (x > y)swap(x,y);
int xx = find(x);
int yy = find(y);
if (xx != yy){
fa[yy] = xx;
}
}
int main(){
int n;
scanf("%d",&n);
memset(b,-1,sizeof b);
for (int i = 0; i <= n; ++i)fa[i] = i;
for (int i = 1; i <= n; ++i){
scanf("%d",&a[i]);
}
for (int i = 1; i <= n; ++i){
scanf("%d",&ord[i]);
}
ans.push_back(0);
ll Max = -1;
for (int i = n; i >= 1; --i){
int pos=ord[i];
b[pos] = a[pos];
ll t;
c[pos] += a[pos];
t = a[pos];
if (b[pos+1] != -1){
add(pos,pos+1);
c[pos] += c[pos+1];
t = c[pos];
}
if (b[pos-1] != -1){
int fa = find(pos-1);
add(fa,pos);
c[fa] += c[pos];
t = c[fa];
}
if (t > Max){
Max = t;
}
ans.push_back(Max);
}
reverse(ans.begin(),ans.end());
int len = ans.size();
for (int i = 1; i < len; ++i){
printf("%I64d\n",ans[i]);
}
// printf("\n");
return 0;
}