hdu-3397 Sequence operation 线段树多种标记
Posted fzl194
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu-3397 Sequence operation 线段树多种标记相关的知识,希望对你有一定的参考价值。
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3397
题目大意:
0 a b表示a-b区间置为0
1 a b表示a-b区间置为1
2 a b表示a-b区间中的0变成1,1变成0
3 a b表示a-b区间中的1的数目
4 a b表示a-b区间中最长连续1的长度
解题思路:
线段树多种标记。
需要处理的东西比较多:
做题的时候发现一个问题:
我的宏定义Max不可以用于函数,尤其是递归函数,这样会使得同一函数重复调用好几遍,递归函数的话更会超时。
1 #include<bits/stdc++.h> 2 #define ios ios::sync_with_stdio(false);//不可再使用scanf printf 3 #define Max(a, b) ((a) > (b) ? (a) : (b))//禁用于函数,会超时 4 #define Min(a, b) ((a) < (b) ? (a) : (b)) 5 #define Mem(a) memset(a, 0, sizeof(a)) 6 #define Dis(x, y, x1, y1) ((x - x1) * (x - x1) + (y - y1) * (y - y1)) 7 #define MID(l, r) ((l) + ((r) - (l)) / 2) 8 #define lson ((o)<<1) 9 #define rson ((o)<<1|1) 10 #pragma comment(linker, "/STACK:102400000,102400000")//栈外挂 11 using namespace std; 12 inline int read() 13 { 14 int x=0,f=1;char ch=getchar(); 15 while (ch<‘0‘||ch>‘9‘){if (ch==‘-‘) f=-1;ch=getchar();} 16 while (ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} 17 return x*f; 18 } 19 20 typedef long long ll; 21 const int maxn = 100000 + 10; 22 const int MOD = 1000000007;//const引用更快,宏定义也更快 23 24 struct node 25 { 26 int l, r;//左右区间 27 int ls0, rs0, ms0;//左连续的0,右连续的0,区间最大连续的0 28 int ls1, rs1, ms1;//左连续的1,右连续的1,区间最大连续的1 29 int sum0, sum1;//区间0 1数目 30 int lazy, Xor;//懒惰标记和异或标记 31 }tree[maxn << 2]; 32 int a[maxn]; 33 void pushup(int o) 34 { 35 if(tree[o].l == tree[o].r)return;//叶子节点直接返回 36 //根据子节点的信息,更新父节点信息 37 38 //更新0: 39 int lc = lson, rc = rson; 40 tree[o].ls0 = tree[lc].ls0; 41 tree[o].rs0 = tree[rc].rs0; 42 if(tree[lc].ls0 == tree[lc].r - tree[lc].l + 1) 43 tree[o].ls0 += tree[rc].ls0;//左节点左连续的0为区间长度 那么根节点左连续的0需要再加上右节点左连续的0 44 if(tree[rc].rs0 == tree[rc].r - tree[rc].l + 1) 45 tree[o].rs0 += tree[lc].rs0; 46 tree[o].ms0 = Max(Max(tree[lc].ms0, tree[rc].ms0), tree[lc].rs0 + tree[rc].ls0);//最大连续0 = Max(左节点最大连续0, 右节点最大连续0,中间最大连续0) 47 tree[o].sum0 = tree[lc].sum0 + tree[rc].sum0; 48 //更新1 49 tree[o].ls1 = tree[lc].ls1; 50 tree[o].rs1 = tree[rc].rs1; 51 if(tree[lc].ls1 == tree[lc].r - tree[lc].l + 1) 52 tree[o].ls1 += tree[rc].ls1;//左节点左连续的0为区间长度 那么根节点左连续的0需要再加上右节点左连续的0 53 if(tree[rc].rs1 == tree[rc].r - tree[rc].l + 1) 54 tree[o].rs1 += tree[lc].rs1; 55 tree[o].ms1 = Max(Max(tree[lc].ms1, tree[rc].ms1), tree[lc].rs1 + tree[rc].ls1);//最大连续0 = Max(左节点最大连续0, 右节点最大连续0,中间最大连续0) 56 tree[o].sum1 = tree[lc].sum1 + tree[rc].sum1; 57 } 58 void XOR(int o) 59 { 60 swap(tree[o].ls0, tree[o].ls1); 61 swap(tree[o].rs0, tree[o].rs1); 62 swap(tree[o].ms0, tree[o].ms1); 63 swap(tree[o].sum0, tree[o].sum1); 64 } 65 void pushdown(int o)//标记下传 66 { 67 if(tree[o].l == tree[o].r)return; 68 if(tree[o].lazy != -1)//区间覆盖0或者1 69 { 70 int lc = lson, rc = rson, len = tree[o].r - tree[o].l + 1; 71 tree[lc].lazy = tree[rc].lazy = tree[o].lazy; 72 tree[lc].Xor = tree[rc].Xor = 0; 73 74 //左节点长度为(len+1) / 2 右节点长度为len/2 75 //左 76 tree[lc].ls0 = tree[lc].rs0 = tree[lc].ms0 = tree[o].lazy ? 0 : (len + 1) / 2; 77 tree[lc].ls1 = tree[lc].rs1 = tree[lc].ms1 = tree[o].lazy ? (len + 1) / 2 : 0; 78 tree[lc].sum0 = tree[o].lazy ? 0 : (len + 1) / 2; 79 tree[lc].sum1 = tree[o].lazy ? (len + 1) / 2 : 0; 80 //右 81 tree[rc].ls0 = tree[rc].rs0 = tree[rc].ms0 = tree[o].lazy ? 0 : (len) / 2; 82 tree[rc].ls1 = tree[rc].rs1 = tree[rc].ms1 = tree[o].lazy ? (len) / 2 : 0; 83 tree[rc].sum0 = tree[o].lazy ? 0 : (len) / 2; 84 tree[rc].sum1 = tree[o].lazy ? (len) / 2 : 0; 85 86 tree[o].lazy = -1;//清除标记 87 } 88 if(tree[o].Xor) 89 { 90 tree[o].Xor = 0; 91 tree[lson].Xor ^= 1; 92 tree[rson].Xor ^= 1; 93 XOR(lson), XOR(rson); 94 } 95 } 96 void build(int o, int l, int r) 97 { 98 tree[o].l = l, tree[o].r = r, tree[o].lazy = -1, tree[o].Xor = 0; 99 if(l == r) 100 { 101 tree[o].ls0 = tree[o].rs0 = tree[o].ms0 = (a[l] == 0); 102 tree[o].ls1 = tree[o].rs1 = tree[o].ms1 = (a[l] == 1); 103 tree[o].sum1 = (a[l] == 1); 104 tree[o].sum0 = (a[l] == 0); 105 return; 106 } 107 int m = MID(l, r); 108 build(lson, l, m); 109 build(rson, m + 1, r); 110 pushup(o); 111 } 112 int flag;//标记类型 113 int ql, qr; 114 void update(int o) 115 { 116 pushdown(o); 117 if(ql <= tree[o].l && qr >= tree[o].r) 118 { 119 if(flag == 2) 120 { 121 tree[o].Xor = 1; 122 XOR(o); 123 } 124 else 125 { 126 int len = tree[o].r - tree[o].l + 1; 127 tree[o].lazy = flag; 128 tree[o].ls0 = tree[o].rs0 = tree[o].ms0 = flag ? 0 : len; 129 tree[o].ls1 = tree[o].rs1 = tree[o].ms1 = flag ? len : 0; 130 tree[o].sum0 = flag ? 0 : len; 131 tree[o].sum1 = flag ? len : 0; 132 } 133 } 134 else 135 { 136 int m = MID(tree[o].l, tree[o].r); 137 if(ql <= m)update(lson); 138 if(qr > m)update(rson); 139 pushup(o); 140 } 141 } 142 143 int query(int o) 144 { 145 pushdown(o); 146 if(ql <= tree[o].l && qr >= tree[o].r) 147 { 148 if(flag == 3)return tree[o].sum1; 149 else return tree[o].ms1; 150 } 151 else 152 { 153 if(qr <= tree[lson].r)return query(lson); 154 if(ql >= tree[rson].l)return query(rson); 155 if(flag == 3)return query(lson) + query(rson); 156 int ans1 = Min(tree[lson].rs1, tree[lson].r - ql + 1) + Min(tree[rson].ls1, qr - tree[rson].l + 1); 157 int ans2 = max(query(lson), query(rson));//用宏定义会超时,因为一直在递归 158 return Max(ans1, ans2); 159 } 160 } 161 162 int main() 163 { 164 int T; 165 scanf("%d", &T); 166 while(T--) 167 { 168 int n, m; 169 scanf("%d%d", &n, &m); 170 for(int i = 1; i <= n; i++)scanf("%d", &a[i]); 171 build(1, 1, n); 172 while(m--) 173 { 174 scanf("%d%d%d", &flag, &ql, &qr); 175 ql++, qr++; 176 if(flag < 3)update(1); 177 else printf("%d ", query(1)); 178 } 179 } 180 return 0; 181 }
以上是关于hdu-3397 Sequence operation 线段树多种标记的主要内容,如果未能解决你的问题,请参考以下文章
hdu-3397 Sequence operation 线段树多种标记
hdu 3397 Sequence operation (线段树 区间合并 多重标记)
HDU 3397 Sequence operation 多标记线段树