poj-2750

13 篇文章 0 订阅
//19188K    672MS   G++

#include <cstdio>
#include <cstring>

#define MAX 100010

using namespace std;

int flowerNum;

inline int max(int a, int b) {
    return a >= b ? a: b;
}

inline int min(int a, int b) {
    return a >= b ? b: a;
}

struct TreeNode {
    int left;
    int right;
    int sum;
    int lmax;
    int rmax;
    int lmin;
    int rmin;
    int nmax;
    int nmin;
    int max;
    int min;
    char complete_used;
};

typedef struct TreeNode TreeNode;
TreeNode tree[MAX<<2];

void buildTree(int left, int right, int pos) {
    // printf("buildTree %d %d\n", left, right);
    tree[pos].left = left;
    tree[pos].right = right;
    tree[pos].sum = 0;
    tree[pos].lmax = 0;
    tree[pos].rmax = 0;
    tree[pos].lmin = 0;
    tree[pos].rmin = 0;
    tree[pos].nmax = 0;
    tree[pos].nmin = 0;
    tree[pos].max = 0;
    tree[pos].min = 0;
    tree[pos].complete_used = 0;
    if (left == right) {
        return;
    } else {
        int mid = (left+right)>>1;
        buildTree(left, mid, pos<<1);
        buildTree(mid+1, right, pos<<1|1);
    }
}

int updateParentTreeNode(int curNodePos) {
    if (curNodePos == 0) { // reach root
        return 0;
    }
    int parentNodePos = curNodePos>>1;
    int broNodePos = curNodePos%2 ? curNodePos-1: curNodePos+1;
    int leftNodePos = curNodePos%2 ? curNodePos-1: curNodePos;
    int rightNodePos = curNodePos%2 ? curNodePos: curNodePos+1;
    TreeNode & parentNode = tree[parentNodePos];
    TreeNode & broNode = tree[broNodePos];
    TreeNode & curNode = tree[curNodePos];
    TreeNode & leftNode = tree[leftNodePos];
    TreeNode & rightNode = tree[rightNodePos];
    // if 2 child not OK yet
    if (!leftNode.complete_used || !rightNode.complete_used) {
        return 0;
    } else { // update the parent code
        parentNode.sum = leftNode.sum + rightNode.sum;
        parentNode.max = max(leftNode.max, rightNode.max);
        parentNode.min = min(leftNode.min, rightNode.min);
        // if (leftNode.left + 1 < rightNode.right) {
            parentNode.lmax = max(leftNode.lmax, rightNode.lmax + leftNode.sum);
            parentNode.rmax = max(rightNode.rmax, leftNode.rmax + rightNode.sum);
            parentNode.lmin = min(leftNode.lmin, leftNode.sum + rightNode.lmin);
            parentNode.rmin = min(rightNode.rmin, rightNode.sum + leftNode.rmin);
        // } else if (leftNode.left + 1 == rightNode.right){ // length == 2
        //     parentNode.lmax = leftNode.sum; // only take 1 number
        //     parentNode.rmax = rightNode.sum;
        //     parentNode.lmin = leftNode.sum;
        //     parentNode.rmin = rightNode.sum;
        // }
        // if (parentNode.max <= 0) { // all number <= 0, pick the max number
        //     parentNode.nmax = parentNode.max;
        //     parentNode.nmin = parentNode.sum - parentNode.max; // nmin is sum subtract the max number
        // } else if (parentNode.min >= 0) { // all number >= 0, remove the min to get nmax
        //     parentNode.nmax = parentNode.sum - parentNode.min;
        //     parentNode.nmin = parentNode.min; // nmin is min here
        // } else { // numbers compose of negative and non-negative number
            // if (leftNode.left + 1 < rightNode.right) {
                long curMin = min(leftNode.nmin, rightNode.nmin);
                curMin = min(curMin, leftNode.rmin + rightNode.lmin);
                // curMin = min(curMin, leftNode.rmin + rightNode.sum);
                // curMin = min(curMin, leftNode.sum + rightNode.lmin);

                long curMax = max(leftNode.nmax, rightNode.nmax);
                curMax = max(curMax, leftNode.rmax + rightNode.lmax);
                // curMax = max(curMax, leftNode.rmax + rightNode.sum);
                // curMax = max(curMax, leftNode.sum + rightNode.lmax);

                parentNode.nmax = curMax;
                parentNode.nmin = curMin;
            // } else if (leftNode.left + 1 == rightNode.right) { // length == 2
            //     parentNode.nmax = max(leftNode.sum, rightNode.sum);
            //     parentNode.nmin = min(leftNode.sum, rightNode.sum);
            // }
        // }
        parentNode.complete_used = 1;
    }
    // printf("updateParentTreeNode %d %d %d %d %d %d %d\n", parentNode.left,
    //         parentNode.right, parentNode.nmax, parentNode.lmax, parentNode.rmax,
    //         parentNode.lmin, parentNode.rmin);
    return 1;
}

void insertTreeNode(int flowerId, int nodePos, int aVal) {
    int left = tree[nodePos].left;
    int right = tree[nodePos].right;
    // printf("insert %d %d %d\n", left, right, flowerId);
    if (left == right && left == flowerId) { // enter the single flower node
        TreeNode & curTreeNode = tree[nodePos];
        curTreeNode.sum = aVal;
        curTreeNode.max = aVal;
        curTreeNode.min = aVal;
        curTreeNode.nmax = aVal;
        curTreeNode.nmin = aVal;
        curTreeNode.lmax = aVal;
        curTreeNode.lmin = aVal;
        curTreeNode.rmax = aVal;
        curTreeNode.rmin = aVal;
        curTreeNode.complete_used = 1;
        int curNodePos = nodePos;
        while(1) {
            if (!updateParentTreeNode(curNodePos)) {
                break;
            } else {
                curNodePos >>= 1;
            }
        }
    } else {
        int mid = (left + right)>>1;
        if (flowerId <= mid) {
            insertTreeNode(flowerId, nodePos<<1, aVal);
        } else {
            insertTreeNode(flowerId, nodePos<<1|1, aVal);
        }
    }
}

void updateTree(int flowerId, int newAVal, int nodePos) {
    int left = tree[nodePos].left;
    int right = tree[nodePos].right;
    // printf("updateTree %d %d\n", left, right);
    if (left == right) {
        TreeNode & curTreeNode = tree[nodePos];
        curTreeNode.sum = newAVal;
        curTreeNode.max = newAVal;
        curTreeNode.min = newAVal;
        curTreeNode.nmax = newAVal;
        curTreeNode.nmin = newAVal;
        curTreeNode.lmax = newAVal;
        curTreeNode.lmin = newAVal;
        curTreeNode.rmax = newAVal;
        curTreeNode.rmin = newAVal;
        int curNodePos = nodePos;
        while(1) {
            if (!updateParentTreeNode(curNodePos)) {
                break;
            } else {
                curNodePos >>= 1;
            }
        }

    } else {
        int mid = (left + right)>>1;
        if (flowerId <= mid) {
            updateTree(flowerId, newAVal, nodePos<<1);
        } else {
            updateTree(flowerId, newAVal, nodePos<<1|1);
        }
    }
}

int output() {
    if(tree[1].nmax<tree[1].sum-tree[1].nmin)  
    {  
        tree[1].nmax=tree[1].sum-tree[1].nmin;  
    }  
    if(tree[1].nmax==tree[1].sum)  
    {  
        return tree[1].sum-tree[1].min;  
    }  
     if(tree[1].nmin==tree[1].sum)  
    {  
        return tree[1].max;  
    }  
    return tree[1].nmax;  
}

int main() {
    while(scanf("%d", &flowerNum) != EOF) {
        memset(tree, 0, sizeof(tree));
        buildTree(1, flowerNum, 1);
        // printf("buildTree OK\n");
        for (int i = 1; i <= flowerNum; i++) {
            int aVal;
            scanf("%d", &aVal);
            insertTreeNode(i, 1, aVal);
        }
        // printf("insert OK\n");
        int changeTime = 0;
        scanf("%d", &changeTime);
        for (int i = 1; i <= changeTime; i++) {
            int A;
            int B;
            scanf("%d %d", &A, &B);
            updateTree(A, B, 1);
            printf("%d\n", output());
        }
    }
}

从线段树角度看,是道简单题,但是因为涉及到了环状数组求连续和(并且还要求了不能全取),因此对于我这样的手残加脑缺,很容易遗漏再加上工作又忙了,以及沉迷game,拖了2,3天,唉,不能倦怠呀。

其实该题本质算是DP,利用子问题的解最终求出大问题,分析直接贴一个写的很好的:

From: http://blog.csdn.net/lin375691011/article/details/19932765

1、在求区间最大和的时候,在这里只有两种情况:

(1)、不同时包括数字1和数字n,只需要求区间的最大和就行了。

(2)、同时包括数字1和数字n,这时候需要求区间的最小和,用所有数减去这个最小和就行。

2、用线段树来处理问题时,我们需要保存以下这些量:

(1)、当前区间所有数之和,它等于半个区间所有数之和半个区间所有数之和

(2)、当前区间的最大数的值,可以由前半个区间的和后半个区间最大数的值来决定。

(3)、当前区间的最小数的值,可以由前半个区间的和后半个区间最小数的值来决定。

(4)、当前区间从左开始的最大连续序列值,可由前半个区间的从左开始的最大连续序列值前半个区间的所有数之和加上后半个区间的从左开始的最大连续序列值决定。

(5)、当前区间从右开始的最大连续序列值,可由后半个区间的从右开始的最大连续序列值后半个区间的所有数之和加上前半个区间的从右开始的最大连续序列值决定。

(6)、当前区间从左开始的最小连续序列值,可由前半个区间的从左开始的最小连续序列值前半个区间的所有数之和加上后半个区间的从左开始的最小连续序列值决定。

(7)、当前区间从右开始的最小连续序列值,可由后半个区间的从右开始的最小连续序列值后半个区间的所有数之和加上前半个区间的从右开始的最小连续序列值决定。

(8)、当前区间的最大连续序列值前半区间的最大连续序列值后半区间的最大连续序列值前半区间从右开始最大连续序列值与后半区间从左开始最大连续序列值之和这三个值中的最大值决定。

(9)、当前区间的最小连续序列值前半区间的最小连续序列值后半区间的最小连续序列值前半区间从右开始最小连续序列值与后半区间从左开始最小连续序列值之和这三个值中的最小值决定。

3、当在最后对线段树更新完成后,根节点的最大连续序列的值不一定就是答案。还有三种意外情况:

(1)、当所有数全部为正数的时候,表现为最大的连续序列值等于所有数之和。这时我们需要输出的是所有数之和最小数的差。(因为由题意得最大连续序列不能包括所有数字)

(2)、当所有数全部为负数的时候,表现为最小连续序列的值等于所有数之和。这时候我们需要输出最大数

(3)、当最大连续序列值小于所有数之和减去最小连续序列值时,需要更新最大连续序列值


其中一个重要思路就是考虑首尾相连的数,这样就要求出最小的连续数组和


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值