【题意】
给你一个序列A, 然后一个序列B,按序列B的顺序依次删除第B[i]个数,问你当前最大连续字段和是多少,这段和不能包括被删除的数。
例如
4
1 3 2 5
3 4 1 2
删除第B[1] = 3个数事,最大字段和是第四个数5,然后依次是4 3 0.
【分析】
先来说说不靠谱的二叉树吧,在第32个点超时了。
我的思路是,每次删除一个数,必然会把一个区间分成两个区间,这样就可以看成这个节点分成两个节点,节点的信息维护区间左端点右端点,和区间最大字段和。每次删除一个数,就会衍生出两个节点,每个节点的最大字段和就两个子节点的最大字段和的最大值。理想情况下是nlogn的复杂度,但是退化成链的情况下复杂度就是n^2了。
代码
#include<cstdio>
#include<algorithm>
using namespace std;
struct node{
long long l, r, maxi;
long long lson, rson;
} a[1000001];
long long c[1000001];
long long f[1000001];
long long tot = 1;
long long NewNode(long long root, int l, int r){
a[root].l = l;
a[root].r = r;
a[root].maxi = f[r] - f[l - 1];
a[root].lson = a[root].rson = 0;
return root;
}
void updata(long long root){
a[root].maxi = max(a[a[root].lson].maxi, a[a[root].rson].maxi);
}
void dfs(long long root, long long k){
//printf("%d %d %d %d\n", root, a[root].l, a[root].r, a[root].maxi);
//getchar();
if(a[root].l == a[root].r) {
a[root].maxi = 0;
}else
if(a[root].lson == 0 && a[root].rson == 0){
a[root].lson = NewNode(++tot, a[root].l, k - 1);
a[root].rson = NewNode(++tot, k + 1, a[root].r);
}else{
if(a[root].lson && k <= a[a[root].lson].r){
dfs(a[root].lson, k);
}
else if(a[root].rson && k >= a[a[root].rson].l){
dfs(a[root].rson, k);
}
}
updata(root);
}
int main(){
long long n;
scanf("%lld", &n);
for(int i = 1; i <= n; i++){
scanf("%lld", &c[i]);
f[i] = f[i - 1] + c[i];
}
NewNode(1, 1, n);
for(int i = 1; i <= n; i++){
long long k;
scanf("%lld", &k);
dfs(1, k);
printf("%lld\n", a[1].maxi);
}
return 0;
}
正解是并查集。倒着思考,删除一个数就加上一个数,没加入一个数就判断一下能不能吧它左右两边连起来。就是并查集了。
代码(记得要用long long)
#include<cstdio>
#include<algorithm>
using namespace std;
long long f[200001];
long long a[200011];
long long c[200001];
long long s[200001];
long long flag[200001];
long long ans[200001];
long long n, maxi = 0;
long long find(long long k){
if(f[k] == k) return k;
else f[k] = find(f[k]);
return f[k];
}
int main(){
scanf("%lld", &n);
for(int i = 1; i <= n; i++){
f[i] = i;
scanf("%lld", &a[i]);
}
for(int i = 1; i <= n; i++){
scanf("%lld", &c[i]);
}
for(int i = n; i > 0; i--){
ans[i] = maxi;
flag[c[i]] = 1;
s[c[i]] = s[find(c[i] - 1)] + s[find(c[i] + 1)] + a[c[i]];
maxi = max(maxi, s[c[i]]);
if(flag[c[i] - 1]) f[find(c[i] - 1)] = c[i];
if(flag[c[i] + 1]) f[find(c[i] + 1)] = c[i];
}
for(int i = 1; i <= n; i++) {
printf("%lld\n", ans[i]);
}
return 0;
}