题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5316
1 1 1 1 0 1 1
1
题意:
给出 n 个点和 m 个操作;
1:1 a b 将 a 点的值改成 b
2: 0 a b 查询子区间 a 到 b 之间最大的子序列和(这个子序列(可以不连续)中的相邻的元素的原来的下标奇偶性都不同)
PS:
官方题解:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define LL long long #define lson l , mid , rt << 1 #define rson mid + 1 , r , rt << 1 | 1 //lson和rson分辨表示结点的左儿子和右儿子 //rt表示当前子树的根(root),也就是当前所在的结点 const int maxn = 100000+7; struct node { int has[2][2];//是否有这种情况 LL val[2][2];//该情况的最大值 } tre[maxn<<2]; int max(int x,int y) { if(x > y) return x; return y; } //合并 node UNION(node a,node b) { node c; //四种起始和终止情况可以直接继承于左儿子或右儿子的对应情况 for(int i = 0; i <= 1; i++) { for(int j = 0; j <= 1; j++) { c.has[i][j] = a.has[i][j] + b.has[i][j]; if(a.has[i][j] && b.has[i][j]) c.val[i][j] = max(a.val[i][j], b.val[i][j]); else if(a.has[i][j]) c.val[i][j] = a.val[i][j]; else if(b.has[i][j]) c.val[i][j] = b.val[i][j]; } } //四种情况由左儿子和右儿子的情况合并。 //如奇始奇终可以由左儿子的奇始奇终和右儿子的偶始奇终合并 //也可以由左儿子的奇始偶终和右儿子的奇始奇终合并,,以此类推 for(int i = 0; i <= 1; i++) { for(int j = 0; j <= 1; j++) { for(int k = 0; k <= 1; k++) { if(a.has[i][j] && b.has[!j][k]) { if(c.has[i][k]) { c.val[i][k] = max(c.val[i][k], a.val[i][j]+b.val[!j][k]); } else { c.has[i][k] = 1; c.val[i][k]=a.val[i][j]+b.val[!j][k]; } } } } } return c; } void PushUP(int rt) { tre[rt] = UNION(tre[rt<<1],tre[rt<<1|1]); } void build(int l,int r,int rt) { memset(tre[rt].has,0,sizeof(tre[rt].has)); if (l == r) { int tt; scanf("%d",&tt); tre[rt].has[l%2][l%2] = 1; tre[rt].val[l%2][l%2] = tt; return ; } int mid = (l + r) >> 1; build(lson); build(rson); PushUP(rt); } void update(int p,int sc,int l,int r,int rt) { if (l == r) //叶节点 { memset(tre[rt].has,0,sizeof(tre[rt].has)); tre[rt].has[l%2][l%2] = 1; tre[rt].val[l%2][l%2] = sc; return ; } int mid = (l + r) >> 1; if (p <= mid)//递归更新左子树或者右子树 update(p , sc , lson); else update(p , sc , rson); PushUP(rt); } node query(int L,int R,int l,int r,int rt) { if (L <= l && r <= R) { return tre[rt]; } int flag1 = 0, flag2 = 0; node ans1, ans2; int mid = (l + r) >> 1; if (L <= mid) //往左走 { ans1 = query(L , R , lson); flag1 = 1; } if (mid < R)//往右走 { ans2 = query(L , R , rson); flag2 = 1; } if(!flag1) { return ans2; } if(!flag2) { return ans1; } return UNION(ans1,ans2); } int main() { int t; int N , M; scanf("%d",&t); while(t--) { scanf("%d%d",&N,&M); build(1 , N , 1); //建树 while(M--) { int op, a , b; scanf("%d%d%d",&op,&a,&b); if(op == 1) { update(a , b , 1 , N , 1); } else if (op == 0) { node t = query(a , b , 1 , N , 1); LL ans; int flag = 0; for(int i = 0; i <= 1; i++) { for(int j = 0; j <= 1; j++) { if(t.has[i][j]) { if(flag == 0) { ans = t.val[i][j]; flag=1; } else ans = max(ans, t.val[i][j]); } } } printf("%lld\n",ans); } } } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
HDU 5316 Magician(线段树区间合并, 子序列最值 多校2015啊)
原文地址:http://blog.csdn.net/u012860063/article/details/47134499