线段树 或者 并查集 Intel Code Challenge Elimination Round (Div.1 + Div.2, combined) C

http://codeforces.com/contest/722/problem/C

题目大意:给你一个串,每次删除串中的一个pos,问剩下的串中,连续的最大和是多少。

思路一:正方向考虑问题,那么就线段树+分类讨论一下就好了,然后代码中flag表示能否转移

 

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define haha printf("haha\n")
const int maxn = 100000 + 5;
struct Tree{
    bool lf, rf;
    bool flag;
    LL val, lval, rval;
}tree[maxn << 2];
int n;
int b[maxn];

inline void push_up(int o){
    int lb = o << 1, rb = o << 1 | 1;
    if (tree[lb].flag && tree[rb].flag){
        tree[o].lf = tree[o].rf = true;
        tree[o].lval = tree[o].rval = tree[o].val = tree[lb].val + tree[rb].val;
        return ;
    }
    tree[o].flag = false;

    if (tree[lb].lf == false) tree[o].lf = false, tree[o].lval = 0;
    else {
        tree[o].lf = true;
        if (tree[lb].flag && tree[rb].lf) tree[o].lval = tree[lb].lval + tree[rb].lval;
        else tree[o].lval = tree[lb].lval;
    }

    if (tree[rb].rf == false) tree[o].rf = false, tree[o].rval = 0;
    else {
        tree[o].rf = true;
        if (tree[rb].flag && tree[lb].rf) tree[o].rval = tree[rb].rval + tree[lb].rval;
        else tree[o].rval = tree[rb].rval;
    }

    tree[o].val = max(tree[lb].val, tree[rb].val);
    if (tree[lb].rf && tree[rb].lf){
        tree[o].val = max(tree[o].val, tree[lb].rval + tree[rb].lval);
    }

}

void build_tree(int l, int r, int o){
    if (l == r) {
        LL val;
        scanf("%lld", &val);
        tree[o].val = tree[o].lval = tree[o].rval = val;
        tree[o].flag = tree[o].lf = tree[o].rf = true;
        return ;
    }
    tree[o].lf = tree[o].rf = tree[o].flag = true;
    int mid = (l + r) / 2;
    if (l <= mid) build_tree(l, mid, o << 1);
    if (r > mid) build_tree(mid + 1, r, o << 1 | 1);
    push_up(o);
}

void update(int l, int r, int pos, int o){
    if (l == r && l == pos){
        tree[o].val = 0;
        tree[o].flag = tree[o].lf = tree[o].rf = false;
        return ;
    }
    int mid = (l + r) / 2;
    if (pos <= mid) update(l, mid, pos, o << 1);
    if (pos > mid) update(mid + 1, r, pos, o << 1 | 1);
    push_up(o);
}

int main(){
    scanf("%d", &n);
    build_tree(1, n, 1);

    for (int i = 1; i <= n; i++){
        int pos; scanf("%d", &pos);
        update(1, n, pos, 1);
        printf("%lld\n", tree[1].val);
    }
    return 0;
}
View Code

 

思路二:逆向考虑,使用并查集,因为最初是0,所以我们只需要逆向考虑就好了。

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define haha printf("haha\n")
const int maxn = 1e5 + 5;
LL a[maxn], b[maxn], sum[maxn], ans[maxn];
bool vis[maxn];
int n;
int par[maxn];

int pfind(int x){
    if (x == par[x]) return x;
    return par[x] = pfind(par[x]);
}

void unite(int x, int y){
    x = pfind(x), y = pfind(y);
    par[x] = y;
    sum[y] += sum[x];
}

int main(){
    cin >> n;
    for (int i = 1; i <= n; i++) {
        par[i] = i;
        scanf("%lld", a + i);
        sum[i] = a[i];
    }
    for (int i = 1; i <= n; i++)
        scanf("%d", b + i);
    LL res = 0;
    for (int i = n; i >= 1; i--){
        ans[i] = res;
        if (vis[b[i] + 1]) unite(b[i], b[i] + 1);
        if (vis[b[i] - 1]) unite(b[i], b[i] - 1);
        vis[b[i]] = true;
        res = max(res, sum[pfind(b[i])]);
    }
    for (int i = 1; i <= n; i++)
        cout << ans[i] << endl;
    return 0;
}
View Code

 

posted @ 2016-10-02 10:54  知る奇迹に  阅读(121)  评论(0编辑  收藏  举报