hdu 3397 Sequence operation 线段树 区间更新 区间合并
Posted Pacify
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 3397 Sequence operation 线段树 区间更新 区间合并相关的知识,希望对你有一定的参考价值。
题意:
5种操作,所有数字都为0或1
0 a b:将[a,b]置0
1 a b:将[a,b]置1
2 a b:[a,b]中的0和1互换
3 a b:查询[a,b]中的1的数量
4 a b:查询[a,b]中的最长连续1串的长度
这题看题目就很裸,综合了区间更新,区间合并
我一开始把更新操作全放一个变量,但是在push_down的时候很麻烦,情况很多,容易漏,后来改成下面的
更新的操作可以分为两类,一个是置值(stv),一个是互换(swp)。如果stv!=-1,则更新儿子节点的stv,并将儿子的swp=0。如果swp=1,这里要注意一点,不是把儿子的swp赋值为1,而是与1异或!!!因为如果儿子的swp本为1,再互换一次,两个互换就相当于值没有变了。
注意下细节就行了
#include <bits/stdc++.h> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 using namespace std; const int MAXN = 111111; struct Node { int num1, stv, swp; int mx0, lmx0, rmx0; int mx1, lmx1, rmx1; } tr[MAXN<<2]; void changeto(int rt, int to,int len) { tr[rt].mx0 = tr[rt].lmx0 = tr[rt].rmx0 = to? 0 : len; tr[rt].mx1 = tr[rt].lmx1 = tr[rt].rmx1 = tr[rt].num1 = to? len : 0; } void exchange(int rt, int len) { tr[rt].num1 = len - tr[rt].num1; swap(tr[rt].mx0, tr[rt].mx1); swap(tr[rt].lmx0, tr[rt].lmx1); swap(tr[rt].rmx0, tr[rt].rmx1); } void push_down(int rt, int len) { if(tr[rt].stv != -1) { tr[rt<<1].stv = tr[rt<<1|1].stv = tr[rt].stv; tr[rt<<1].swp = tr[rt<<1|1].swp = 0; changeto(rt<<1, tr[rt].stv, len-(len>>1)); changeto(rt<<1|1, tr[rt].stv, len>>1); tr[rt].stv = -1; } if(tr[rt].swp == 1) { tr[rt<<1].swp ^= 1; tr[rt<<1|1].swp ^= 1; exchange(rt<<1, len-(len>>1)); exchange(rt<<1|1, len>>1); tr[rt].swp = 0; } } void push_up(int rt, int len) { tr[rt].num1 = tr[rt<<1].num1 + tr[rt<<1|1].num1; tr[rt].lmx0 = tr[rt<<1].lmx0; tr[rt].rmx0 = tr[rt<<1|1].rmx0; if(tr[rt].lmx0 == len - (len >> 1)) tr[rt].lmx0 += tr[rt<<1|1].lmx0; if(tr[rt].rmx0 == len >> 1) tr[rt].rmx0 += tr[rt<<1].rmx0; tr[rt].mx0 = max(tr[rt<<1].rmx0 + tr[rt<<1|1].lmx0, max(tr[rt<<1].mx0, tr[rt<<1|1].mx0)); tr[rt].lmx1 = tr[rt<<1].lmx1; tr[rt].rmx1 = tr[rt<<1|1].rmx1; if(tr[rt].lmx1 == len - (len >> 1)) tr[rt].lmx1 += tr[rt<<1|1].lmx1; if(tr[rt].rmx1 == len >> 1) tr[rt].rmx1 += tr[rt<<1].rmx1; tr[rt].mx1 = max(tr[rt<<1].rmx1 + tr[rt<<1|1].lmx1, max(tr[rt<<1].mx1, tr[rt<<1|1].mx1)); } void build(int l, int r, int rt) { tr[rt].stv = -1; tr[rt].swp = 0; if(l == r) { scanf("%d", &tr[rt].num1); tr[rt].mx0 = tr[rt].lmx0 = tr[rt].rmx0 = tr[rt].num1 ^ 1; tr[rt].mx1 = tr[rt].lmx1 = tr[rt].rmx1 = tr[rt].num1; return; } int m = (l + r) >> 1; build(lson); build(rson); push_up(rt, r-l+1); } void update(int L, int R, int op, int l, int r, int rt) { if(L <= l && r <= R) { if(op == 0 || op == 1) { changeto(rt, op, r-l+1); tr[rt].stv = op; tr[rt].swp = 0; } else { exchange(rt, r-l+1); tr[rt].swp ^= 1; } return; } push_down(rt, r-l+1); int m = (l + r) >> 1; if(m >= L) update(L, R, op, lson); if(m < R) update(L, R, op, rson); push_up(rt, r-l+1); } int query1(int L, int R, int l, int r, int rt) { if(L <= l && r <= R) return tr[rt].num1; push_down(rt, r-l+1); int m = (l + r) >> 1; int ret = 0; if(m >= L) ret += query1(L, R, lson); if(m < R) ret += query1(L, R, rson); return ret; } int query2(int L, int R, int l, int r, int rt) { if(L <= l && r <= R) return tr[rt].mx1; push_down(rt, r-l+1); int m = (l + r) >> 1; int ret = 0; if(m >= L) ret = max(ret, query2(L, R, lson)); if(m < R) ret = max(ret, query2(L, R, rson)); ret = max(ret, min(tr[rt<<1].rmx1, m-L+1) + min(tr[rt<<1|1].lmx1, R-m)); return ret; } int main() { // freopen("in.txt", "r", stdin); int T; scanf("%d", &T); while(T--) { int n, m; scanf("%d%d", &n, &m); build(0, n-1, 1); while(m--) { int op, x, y; scanf("%d%d%d", &op, &x, &y); if(op <= 2) update(x, y, op, 0, n-1, 1); else if(op == 3) printf("%d\n", query1(x, y, 0, n-1, 1)); else printf("%d\n", query2(x, y, 0, n-1, 1)); } } return 0; }
以上是关于hdu 3397 Sequence operation 线段树 区间更新 区间合并的主要内容,如果未能解决你的问题,请参考以下文章
hdu-3397 Sequence operation 线段树多种标记
hdu 3397 Sequence operation (线段树 区间合并 多重标记)
HDU 3397 Sequence operation 多标记线段树