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\n", query(1));
178         }
179     }
180     return 0;
181 }

原文地址:https://www.cnblogs.com/fzl194/p/9567091.html

时间: 2024-10-13 13:12:17

hdu-3397 Sequence operation 线段树多种标记的相关文章

HDU 3397 Sequence operation 线段树

线段树大杂烩~ 各种操作都有,细心点不难1A #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; #define lson rt<<1,l,mid #define rson rt<<1|1,mid + 1,r const int maxn = 1e5 + 10; int lmax[maxn

HDU 3397 Sequence operation (线段树,成段更新,区间合并)

http://acm.hdu.edu.cn/showproblem.php?pid=3397 Sequence operation Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5801    Accepted Submission(s): 1713 Problem Description lxhgww got a sequence

hdu 3397 Sequence operation (线段树 区间合并 多重标记)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397 题意: 给你一串01串,有5种操作 0. 区间全部变为0 1.区间全部变为1 2.区间异或 3.询问区间1的个数 4.询问区间被最长连续1的长度 思路: 这5个操作都是比较基础的线段树操作,难点在于有两种修改操作,这类题之前也写过,之前是乘法和加法,这个是区间亦或和区间更新值,但是思路是可以借鉴的,我们要推出这两个操作的关系,这样才能维护好这两个标记,我们用两个标记:same , rev ,分别表

Hdu 3397 Sequence operation(线段树多操作,Lazy思想,成段更新)

Sequence operation Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 6397    Accepted Submission(s): 1899 Problem Description lxhgww got a sequence contains n characters which are all '0's or '1

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,并将儿子的sw

HDU 3397 Sequence operation(线段树)

HDU 3397 Sequence operation 题目链接 题意:给定一个01序列,有5种操作 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最长的长度 思路:线段树线段合并.须要两个延迟标记一个置为01,一个翻转,然后因为4操作,须要记录左边最长0.1.右边最长0.1,区间最长0.1,然后区间合并去搞就可以 代码: #include <cstdi

【线段树】HDU 3397 Sequence operation 区间合并

操作 Change operations: 0 a b change all characters into '0's in [a , b] 1 a b change all characters into '1's in [a , b] 2 a b change all '0's into '1's and change all '1's into '0's in [a, b] Output operations: 3 a b output the number of '1's in [a,

HDU 3397 Sequence operation(线段树&#183;成段更新&#183;区间合并&#183;混合操作)

题意  给你一个只有0, 1的数组  有这些操作 0. 将[a, b]区间的所有数都改为0 1. 将[a, b]区间的所有数都改为1 2. 将[a, b]区间的所有数都取反 即与1异或 3. 输出区间[a, b]中1的个数  即所有数的和 4. 输出区间[a, b]中最大连续1的长度 对于所有的3, 4操作输出对应的答案 单个的操作都很简单  但搞在一起就有点恶心了  还好数组里的数只有0和1 线段树维护9个值 对应区间0, 1的最大长度len[i]  对应区间左端点为起点的最大0, 1长度ll

hdu 3397 Sequence operation(线段树:区间更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397 题意:给你一个长度为n的0,1序列,支持下列五种操作, 操作0(0 a b):将a到b这个区间的元素全部置为0. 操作1(1 a b):将a到b这个区间的元素全部置为1. 操作2(2 a b):将a到b这个区间所有的0置为1,所有的1置为0. 操作3(3 a b):查询a到b这个区间1的总数. 操作4(4 a b):查询a到b这个区间连续1的最长长度 本题属于简单的区间更新线段树 重点:0操作