//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)、当最大连续序列值小于所有数之和减去最小连续序列值时,需要更新最大连续序列值。
其中一个重要思路就是考虑首尾相连的数,这样就要求出最小的连续数组和