hdu--3911--线段树<我最近爱上她了>

突然间 觉得 线段树是个很优美的数据结构~~ 太灵活了 通过几个var 可以完成太多功能

这题其实我也想说 好累啊 写的...但似乎 因为它是线段树的缘故就显得很平常了...

这里主要考察了lazy标记---延迟父节点对子节点的更新

这边还算简单的 只需要1个Lazy标记 麻烦的是需要2个 甚至3个的...

这边至于 黑白关系 就是一个 异或运算 可以搞定

要注意下 询问一段区间内 最长的连续的1的个数 必须分成3段来考虑  通过是否包含中点 来划分 左 右 中

虽然 这边是问最长的连续的1的个数 但我有必要记录下最长的连续0的个数 因为这样进行一个Update后 答案就是变成了刚才的最长的连续0的个数

这边我们分别需要考虑一个区间从左边与右边分别来看的 含连续0或1的最长区间 再统一考虑得出一个区间内最长连续0或1的长度

真的  线段树 需要思考的范围很多

这边的话 我分别试了下 2种不同的对于区间进行操作的方式 发现时间上第一种 更加快点

  1 /*
  2 线段树所有节点理论空间值是2n-1,但是实际上所占空间会超过这个数。因为一颗线段树的高度是log(n - 1) + 1,
  3 而线段树是完全二叉树,所以要开够最后一层,所以总的空间就是1+2^1 + ... + 2^(log(n - 1) + 1) = 4(n - 1) - 1。
  4 所以保守要开4倍空间,但是大多数情况下3倍空间也是能过的。
  5 */
  6 #include <iostream>
  7 #include <algorithm>
  8 using namespace std;
  9
 10 const int size = 100010;
 11 struct data  // 1是黑色  0是白色
 12 {
 13     int L;
 14     int R;
 15     int len;
 16     int Lone , Rone , Lzero , Rzero , maxOne  , maxZero;
 17     int color;
 18 }tree[size*4];
 19
 20 void solve( int root )
 21 {
 22     swap( tree[root].Lone , tree[root].Lzero );
 23     swap( tree[root].Rone , tree[root].Rzero );
 24     swap( tree[root].maxOne , tree[root].maxZero );
 25     tree[root].color ^= 1;
 26 }
 27
 28 void pushUp( int root )
 29 {
 30     tree[root].Lone = tree[root<<1].Lone;
 31     if( tree[root<<1].Lone == tree[root<<1].len )
 32         tree[root].Lone += tree[root<<1|1].Lone;
 33
 34     tree[root].Lzero = tree[root<<1].Lzero;
 35     if( tree[root<<1].Lzero == tree[root<<1].len )
 36         tree[root].Lzero += tree[root<<1|1].Lzero;
 37
 38     tree[root].Rone = tree[root<<1|1].Rone;
 39     if( tree[root<<1|1].Rone == tree[root<<1|1].len )
 40         tree[root].Rone += tree[root<<1].Rone;
 41
 42     tree[root].Rzero = tree[root<<1|1].Rzero;
 43     if( tree[root<<1|1].Rzero == tree[root<<1|1].len )
 44         tree[root].Rzero += tree[root<<1].Rzero;
 45
 46     tree[root].maxOne = max( max( tree[root<<1].maxOne , tree[root<<1|1].maxOne ) , tree[root<<1].Rone + tree[root<<1|1].Lone );
 47     tree[root].maxZero = max( max( tree[root<<1].maxZero , tree[root<<1|1].maxZero) , tree[root<<1].Rzero + tree[root<<1|1].Lzero );
 48 }
 49
 50 void pushDown( int root )
 51 {
 52     solve( root<<1 );
 53     solve( root<<1|1 );
 54     tree[root].color = 0;
 55 }
 56
 57 void build( int root , int L , int R )
 58 {
 59     int Mid = ( L + R ) >> 1 , num;
 60     tree[root].L = L;
 61     tree[root].R = R;
 62     tree[root].len = R - L + 1;
 63     tree[root].color = 0;
 64     if( L==R )
 65     {
 66         cin >> num;
 67         if( num == 1 )
 68         {
 69             tree[root].Lone =  tree[root].Rone = tree[root].maxOne = 1;
 70             tree[root].Lzero = tree[root].Rzero = tree[root].maxZero = 0;
 71         }
 72         else
 73         {
 74             tree[root].Lone = tree[root].Rone = tree[root].maxOne = 0;
 75             tree[root].Lzero = tree[root].Rzero = tree[root].maxZero = 1;
 76         }
 77         return;
 78     }
 79     build( root<<1 , L , Mid );
 80     build( root<<1|1 , Mid+1 , R );
 81     pushUp( root );
 82 }
 83
 84 void update( int root , int L , int R )
 85 {
 86     int Mid = ( tree[root].L + tree[root].R ) >> 1;
 87     if( tree[root].L == L && tree[root].R == R )
 88     {
 89         solve( root );
 90         return;
 91     }
 92     if( tree[root].color )
 93         pushDown( root );
 94     if( R <= Mid )
 95         update( root<<1 , L , R );
 96     else if( L >= Mid+1 )
 97         update( root<<1|1 , L , R );
 98     else
 99     {
100         update( root<<1 , L , Mid );
101         update( root<<1|1 , Mid+1 , R );
102     }
103     pushUp( root );
104 }
105
106 int query( int root , int L , int R )
107 {
108     int a = 0 , b = 0 , var = 0;
109     int Mid = ( tree[root].L + tree[root].R ) >> 1;
110     if( tree[root].L == L && tree[root].R == R )
111     {
112         return tree[root].maxOne;
113     }
114     if( tree[root].color )
115         pushDown( root );
116     if( R <= Mid )
117         return query( root<<1 , L , R );
118     else if( L >= Mid+1 )
119         return query( root<<1|1 , L , R );
120     else
121     {
122         a = query( root<<1 , L , Mid );
123         b = query( root<<1|1 , Mid+1 , R );
124         var = min( Mid - L + 1 , tree[root<<1].Rone ) + min( R - Mid , tree[root<<1|1].Lone );
125         return max( max(a,b) , var );
126     }
127 }
128
129 int main()
130 {
131     cin.sync_with_stdio(false);
132     int n , m , x , y , op;
133     while( cin >> n )
134     {
135         build( 1 , 1 , n );
136         cin >> m;
137         while( m-- )
138         {
139             cin >> op >> x >> y;
140             if( op == 1 )
141             {
142                 update( 1 , x , y );
143             }
144             else
145             {
146                 cout << query( 1 , x , y ) << endl;
147             }
148         }
149     }
150     return 0;
151 }

  1 /*
  2 线段树所有节点理论空间值是2n-1,但是实际上所占空间会超过这个数。因为一颗线段树的高度是log(n - 1) + 1,
  3 而线段树是完全二叉树,所以要开够最后一层,所以总的空间就是1+2^1 + ... + 2^(log(n - 1) + 1) = 4(n - 1) - 1。
  4 所以保守要开4倍空间,但是大多数情况下3倍空间也是能过的。
  5 */
  6 #include <iostream>
  7 #include <algorithm>
  8 using namespace std;
  9
 10 const int size = 100010;
 11 struct data  // 1是黑色  0是白色
 12 {
 13     int L;
 14     int R;
 15     int len;
 16     int Lone , Rone , Lzero , Rzero , maxOne  , maxZero;
 17     int color;
 18 }tree[size*4];
 19
 20 void solve( int root )
 21 {
 22     swap( tree[root].Lone , tree[root].Lzero );
 23     swap( tree[root].Rone , tree[root].Rzero );
 24     swap( tree[root].maxOne , tree[root].maxZero );
 25     tree[root].color ^= 1;
 26 }
 27
 28 void pushUp( int root )
 29 {
 30     tree[root].Lone = tree[root<<1].Lone;
 31     if( tree[root<<1].Lone == tree[root<<1].len )
 32         tree[root].Lone += tree[root<<1|1].Lone;
 33
 34     tree[root].Lzero = tree[root<<1].Lzero;
 35     if( tree[root<<1].Lzero == tree[root<<1].len )
 36         tree[root].Lzero += tree[root<<1|1].Lzero;
 37
 38     tree[root].Rone = tree[root<<1|1].Rone;
 39     if( tree[root<<1|1].Rone == tree[root<<1|1].len )
 40         tree[root].Rone += tree[root<<1].Rone;
 41
 42     tree[root].Rzero = tree[root<<1|1].Rzero;
 43     if( tree[root<<1|1].Rzero == tree[root<<1|1].len )
 44         tree[root].Rzero += tree[root<<1].Rzero;
 45
 46     tree[root].maxOne = max( max( tree[root<<1].maxOne , tree[root<<1|1].maxOne ) , tree[root<<1].Rone + tree[root<<1|1].Lone );
 47     tree[root].maxZero = max( max( tree[root<<1].maxZero , tree[root<<1|1].maxZero) , tree[root<<1].Rzero + tree[root<<1|1].Lzero );
 48 }
 49
 50 void pushDown( int root )
 51 {
 52     solve( root<<1 );
 53     solve( root<<1|1 );
 54     tree[root].color = 0;
 55 }
 56
 57 void build( int root , int L , int R )
 58 {
 59     int Mid = ( L + R ) >> 1 , num;
 60     tree[root].L = L;
 61     tree[root].R = R;
 62     tree[root].len = R - L + 1;
 63     tree[root].color = 0;
 64     if( L==R )
 65     {
 66         cin >> num;
 67         if( num == 1 )
 68         {
 69             tree[root].Lone =  tree[root].Rone = tree[root].maxOne = 1;
 70             tree[root].Lzero = tree[root].Rzero = tree[root].maxZero = 0;
 71         }
 72         else
 73         {
 74             tree[root].Lone = tree[root].Rone = tree[root].maxOne = 0;
 75             tree[root].Lzero = tree[root].Rzero = tree[root].maxZero = 1;
 76         }
 77         return;
 78     }
 79     build( root<<1 , L , Mid );
 80     build( root<<1|1 , Mid+1 , R );
 81     pushUp( root );
 82 }
 83
 84 void update( int root , int L , int R )
 85 {
 86     int Mid = ( tree[root].L + tree[root].R ) >> 1;
 87     if( tree[root].L >= L && tree[root].R <= R )
 88     {
 89         solve( root );
 90         return;
 91     }
 92     if( tree[root].color )
 93         pushDown( root );
 94     if( L <= Mid )
 95         update( root<<1 , L , R );
 96     if( R >= Mid+1 )
 97         update( root<<1|1 , L , R );
 98     pushUp( root );
 99 }
100
101 int query( int root , int L , int R )
102 {
103     int a = 0 , b = 0 , var = 0;
104     int Mid = ( tree[root].L + tree[root].R ) >> 1;
105     if( tree[root].L >= L && tree[root].R <= R )
106     {
107         return tree[root].maxOne;
108     }
109     if( tree[root].color )
110         pushDown( root );
111     if( L <= Mid )
112         a = query( root<<1 , L , R );
113     if( R >= Mid+1 )
114         b = query( root<<1|1 , L , R );
115     var = min( Mid - L + 1 , tree[root<<1].Rone ) + min( R - Mid , tree[root<<1|1].Lone );
116     return max( max(a,b) , var );
117 }
118
119 int main()
120 {
121     cin.sync_with_stdio(false);
122     int n , m , x , y , op;
123     while( cin >> n )
124     {
125         build( 1 , 1 , n );
126         cin >> m;
127         while( m-- )
128         {
129             cin >> op >> x >> y;
130             if( op == 1 )
131             {
132                 update( 1 , x , y );
133             }
134             else
135             {
136                 cout << query( 1 , x , y ) << endl;
137             }
138         }
139     }
140     return 0;
141 }

我应该还会继续做几题 来找感觉 蛮有意思的  =_=

today:

  努力想得到什么东西,其实只要沉着镇静、实事求是,就可以轻易地、神不知鬼不觉地达到目的。

而如果过于使劲,闹得太凶,太幼稚,太没有经验,就哭啊,抓啊,拉啊,像一个小孩扯桌布,

结果却是一无所获,只不过把桌上的好东西都扯到地上,永远也得不到了。

时间: 2024-10-17 00:29:38

hdu--3911--线段树<我最近爱上她了>的相关文章

HDU 3911 线段树区间合并

北京赛区快了,准备袭击数据结构和图论.倒计时 18天,线段树区间合并.维护一个最长连续.. 题意:给一个01串,以下有一些操作,问区间最长的连续的1的个数 思路:非常裸的线段树区间合并 #include<iostream> #include<cstdio> #include<map> #include<set> #include<cmath> #define lson id << 1 #define rson id <<

HDU 4893 线段树裸题

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2512    Accepted Submission(s): 751 Problem Description Recently, Doge got a funny birthday present from his new friend, Pro

HDU 4902 线段树(区间更新)

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 353    Accepted Submission(s): 169 Problem Description There is an old country and the king fell in love with a devil. The devil alw

hdu 4893 线段树 --- 也是两个变 类似双标记

http://acm.hdu.edu.cn/showproblem.php?pid=4893 开始的时候,我按双标记,WA了一下午,搞不定,我是用的两个标记add--表示当前结点中有值发生变化,flag,斐波那契的懒惰标记,但是估计是我自己处理的有问题,一直不对 参考了别人的代码,写法还是很不错的,Add变量维护的是,完全变成Fibonacci的时候的和,---回头我再重新写一遍 #include <cstdio> #include <cstring> #include <a

HDU 4902 线段树||暴力

给定一个序列,两种操作 1:把一段变成x. 2:把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列. 线段树解法:用lazy标记下即可,优化方法还是很巧妙的, Accepted 4902 515MS 3308K 1941 B C++ #include "stdio.h" #include "string.h" struct node { int l,r,x;// 在叶子节点代表值,树节点代表成端更新的lazy操作. }data[400010]

HDU 4302 线段树单点更新,维护区间最大最小值

http://acm.hdu.edu.cn/showproblem.php?pid=4302 Problem Description Holedox is a small animal which can be considered as one point. It lives in a straight pipe whose length is L. Holedox can only move along the pipe. Cakes may appear anywhere in the p

HDU 3397 线段树 双懒惰标记

这个是去年遗留历史问题,之前思路混乱,搞了好多发都是WA,就没做了 自从上次做了大白书上那个双重懒惰标记的题目,做这个就思路很清晰了 跟上次大白上那个差不多,这个也是有一个sets标记,代表这个区间全部置为0或者1,没有置位的时候为-1 还有个rev标记,代表翻转操作,0代表当前不翻,1代表当前翻 要注意一下优先级,发现有不同的弄法,我是这个弄得,有set操作的时候,set标记设值,并把当前节点的rev标记设为0,因为不管要不要rev,当前set操作肯定直接覆盖了 rev操作不改变set操作,在

hdu 2795 线段树--点更新

http://acm.hdu.edu.cn/showproblem.php?pid=2795 多校的第一场和第三场都出现了线段树,比赛期间没做,,这两天先做几道热身下,然后31号之前把那两道多校的线段树都搞了,这是一道热身题 关键是建模: 首先一定看清楚题目构造的场景,看有什么特点--------会发现,如果尽量往左上放置的话,那么由于 the i-th announcement is a rectangle of size 1 * wi.,完全可以对h建立线段树,表示一行,结点里的l,r就表示

HDU 1698 线段树(区间染色)

Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 16255    Accepted Submission(s): 8089 Problem Description In the game of DotA, Pudge’s meat hook is actually the most horrible thing f

HDU 3642 线段树+离散化+扫描线

题意:给你N个长方体的左下角和右上角坐标,问你空间中有多少体积是被大于两个不同的立方体覆盖的.x,y~10^6 z~500 考虑到给的z比较小,所以可以直接枚举z,然后跑二维的扫描线就好. 关于处理被不同的线段覆盖三次的问题,可以维护四个信息,cnt,once,twice,more,然后相互推出结果就好. #include <cstdio> #include <cstring> #include <vector> #include <algorithm> #