问题描述:
有一个标有长度为(0至N)的条形黑板,一些小朋友在黑板上画线(黑板可看成一条线),但另一些则会擦掉一些,经过一段时间后,请统计黑板上的线到底有多长。
输入:
第一行3个整数分别表示起刻度,结束刻度(两个刻度差小于10000000),操作次数(不超过10万次)。
接下来操作次数行,每行3个数,第一个数为0表示画线段,为1则是擦去,后面两个数表示起点刻度和终点刻度。
输出:
N行即每次操作后线段的长度。
样例:
输入:
1 100 2
0 30 92
0 28 34
输出:
62
64
1 #include <algorithm> 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <string> 6 #include <cstdio> 7 #include <queue> 8 using namespace std ; 9 10 int sta , end , n , len , tot ; 11 struct ide{ 12 int l , r , cd , lazy ; 13 } tree[4000003]; 14 int z , a, b ; 15 16 17 inline void Init( ) { 18 freopen( "10131.in" , "r" , stdin ) ; 19 freopen( "10131.out" , "w" , stdout ) ; 20 } 21 22 23 void set_lazy ( int num , int z , int len ) { 24 if( z == -1 ) return ; 25 tree[num].cd = z * len ; 26 tree[num].lazy = z ; 27 28 } 29 30 31 void down_lazy ( int num , int l , int r ) { 32 int mid = ( l+r ) >> 1; 33 set_lazy( tree[num].l, tree[num].lazy, mid-l+1 ); 34 set_lazy( tree[num].r, tree[num].lazy, r-mid ); 35 tree[num].lazy = -1; 36 } 37 38 39 void update( int num , int l , int r ) { 40 if( l != r ) { 41 if( !tree[num].l ) tree[num].l = ++tot ; 42 if( !tree[num].r ) tree[num].r = ++tot ; 43 } 44 if ( a<=l && b>=r ) { set_lazy( num, z, r-l+1 ) ; return ; } 45 int mid = ( r + l ) >> 1 ; 46 down_lazy( num , l , r ) ; 47 if( a <= mid ) update( tree[num].l , l , mid ) ; 48 if( b > mid ) update( tree[num].r , mid+1 , r ) ; 49 tree[num].cd = tree[ tree[num].l ].cd + tree[tree[num].r].cd; 50 } 51 52 53 void input( ) { 54 int sta , end , n ; 55 scanf( "%d%d%d" ,&sta , &end , &n ) ; 56 tot = 1 , end -= sta ; 57 for (int i = 1 ; i <= n ; ++i ) { 58 scanf( "%d%d%d",&z, &a, &b ); 59 b -= sta; a -= sta ; a++ ; z ^= 1 ; 60 update(1, 1, end ); 61 printf( "%d ",tree[1].cd ); 62 63 } 64 65 } 66 67 68 69 int main ( ) { 70 // Init( ) ; 71 input( ) ; 72 // sov( ) ; 73 // output( ) ; 74 fclose(stdin); 75 fclose(stdout); 76 return 0 ; 77 }
嗯 ,这道题有就是个很裸的线段树+lazy标记 ,唯一注意的就是其实你开不了那么大的线段树 ,所以可行的办法就是,你要用哪段区间就把哪段开出来 ,然后直接链式记录左右子节点。