CodeForces 722C Destroying Array(并查集和我奇怪的二叉树)

【题意】
给你一个序列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
#include
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
#include
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;
}

你可能感兴趣的:(CodeForces,并查集)