pku 3225 区间 我对线段树延迟标记的一些理解

pku 3225 区间 我对线段树延迟标记的一些理解

这题网上结题报告应该很多了,我也不想多写什么,但是写完这题后,我对延迟标记的更新策略有了更新的理解
这题节点的结构应该算复杂的了
1  struct  tree
2  {
3       int  s,e;
4       char  cover,del,turn,sta;
5  }st[ 65540 * 8 ];
其中除了状态域,总共有3个延迟标记。合法的节点应该是至多存在一个延迟标记。所以我们在push_down的时候,当前节点至多有1个延迟标记,我们也要保证将该标记传递下去以后,儿子节点也要满足至多存在一个延迟的约束,否则我们将无法处理木有优先级的多个标志重叠的情况。例如这题:
 1  void  push( int  pos)
 2  {
 3       if (st[pos].turn)
 4      {
 5          st[pos].sta =! st[pos].sta;
 6          st[pos].turn = 0 ;
 7           if (st[pos].e != st[pos].s)
 8          {
 9               if (st[L].cover) st[L].cover = 0 ,st[L].del = 1 ;
10               else   if (st[L].del) st[L].cover = 1 ,st[L].del = 0 ;
11               else   st[L].turn =! st[L].turn;
12               if (st[R].cover) st[R].cover = 0 ,st[R].del = 1 ;
13               else   if (st[R].del) st[R].cover = 1 ,st[R].del = 0 ;
14               else   st[R].turn =! st[R].turn;
15          }
16      }
17       else   if (st[pos].cover)
18      {
19          st[pos].cover = 0 ;
20          st[pos].sta = 1 ;
21           if (st[pos].e != st[pos].s)
22          {
23              st[L].cover = 1 ;
24              st[L].del = 0 ;
25              st[L].turn = 0 ;
26              st[R].cover = 1 ;
27              st[R].del = 0 ;
28              st[R].turn = 0 ;
29          }
30      }
31       else   if (st[pos].del)
32      {
33          st[pos].del = 0 ;
34          st[pos].sta = 0 ;
35           if (st[pos].e != st[pos].s)
36          {
37              st[L].cover = 0 ;
38              st[L].turn = 0 ;
39              st[L].del = 1 ;
40              st[R].cover = 0 ;
41              st[R].del = 1 ;
42              st[R].turn = 0 ;
43          }
44      }
45  }
所有操作函数的结构都应该是这样的
1  void  insert( int  s, int  e, int  pos)
2  {
3      push(pos);
4       if (st[pos].s == s && st[pos].e == e) st[pos].cover = 1 ;
5       else   if (e <= M) insert(s,e,L);
6       else   if (s >= M + 1 ) insert(s,e,R);
7       else  insert(s,M,L),insert(M + 1 ,e,R);
8  }
因为这题木有向上维护的过程,如果有的话,末尾要加上
push(L),push(R),update(pos);
所有线段树的结构都是如此,更新策略也亦是如此,只要保证节点至多1个延迟标记 的性质,题目就不会错。
最后,附上本题得完整代码,感觉我写的算清楚的了
  1  # include  < stdio.h >
  2  # include  < string .h >
  3  # include  < stdlib.h >
  4  struct  tree
  5  {
  6       int  s,e;
  7       char  cover,del,turn,sta;
  8  }st[ 65540 * 8 ];
  9  # define M ((st[pos].s + st[pos].e) >> 1 )
 10  # define L (pos << 1 )
 11  # define R ((pos << 1 ) + 1 )
 12  void  init( int  s, int  e, int  pos)
 13  {
 14      st[pos].s = s;
 15      st[pos].e = e;
 16      st[pos].cover = st[pos].del = st[pos].turn = st[pos].sta = 0 ;
 17       if (e != s)
 18          init(s,M,L),init(M + 1 ,e,R);
 19  }
 20  void  push( int  pos)
 21  {
 22       if (st[pos].turn)
 23      {
 24          st[pos].sta =! st[pos].sta;
 25          st[pos].turn = 0 ;
 26           if (st[pos].e != st[pos].s)
 27          {
 28               if (st[L].cover) st[L].cover = 0 ,st[L].del = 1 ;
 29               else   if (st[L].del) st[L].cover = 1 ,st[L].del = 0 ;
 30               else   st[L].turn =! st[L].turn;
 31               if (st[R].cover) st[R].cover = 0 ,st[R].del = 1 ;
 32               else   if (st[R].del) st[R].cover = 1 ,st[R].del = 0 ;
 33               else   st[R].turn =! st[R].turn;
 34          }
 35      }
 36       else   if (st[pos].cover)
 37      {
 38          st[pos].cover = 0 ;
 39          st[pos].sta = 1 ;
 40           if (st[pos].e != st[pos].s)
 41          {
 42              st[L].cover = 1 ;
 43              st[L].del = 0 ;
 44              st[L].turn = 0 ;
 45              st[R].cover = 1 ;
 46              st[R].del = 0 ;
 47              st[R].turn = 0 ;
 48          }
 49      }
 50       else   if (st[pos].del)
 51      {
 52          st[pos].del = 0 ;
 53          st[pos].sta = 0 ;
 54           if (st[pos].e != st[pos].s)
 55          {
 56              st[L].cover = 0 ;
 57              st[L].turn = 0 ;
 58              st[L].del = 1 ;
 59              st[R].cover = 0 ;
 60              st[R].del = 1 ;
 61              st[R].turn = 0 ;
 62          }
 63      }
 64  }
 65  void  insert( int  s, int  e, int  pos)
 66  {
 67      push(pos);
 68       if (st[pos].s == s && st[pos].e == e) st[pos].cover = 1 ;
 69       else   if (e <= M) insert(s,e,L);
 70       else   if (s >= M + 1 ) insert(s,e,R);
 71       else  insert(s,M,L),insert(M + 1 ,e,R);
 72  }
 73  void  clear( int  s, int  e, int  pos)
 74  {
 75      push(pos);
 76       if (st[pos].s == s && st[pos].e == e) st[pos].del = 1 ;
 77       else   if (e <= M) clear(s,e,L);
 78       else   if (s >= M + 1 ) clear(s,e,R);
 79       else  clear(s,M,L),clear(M + 1 ,e,R);
 80  }
 81  void  turn( int  s, int  e, int  pos)
 82  {
 83      push(pos);
 84       if (st[pos].s == s && st[pos].e == e) st[pos].turn =! st[pos].turn;
 85       else   if (e <= M) turn(s,e,L);
 86       else   if (s >= M + 1 ) turn(s,e,R);
 87       else  turn(s,M,L),turn(M + 1 ,e,R);
 88  }
 89  int  quarry( int  pos, int  target)
 90  {
 91      push(pos);
 92       if (st[pos].s == target && st[pos].e == target)
 93           return  st[pos].turn ?! st[pos].sta:st[pos].sta;
 94       else   if (target > M)  return  st[pos].turn ?! quarry(R,target):quarry(R,target);
 95       else   return  st[pos].turn ?! quarry(L,target):quarry(L,target);
 96  }
 97  void  print()
 98  {
 99       int  i,last =- 1 ,used = 0 ;
100       for (i = 0 ;i <= 65540 * 2 ;i ++ )
101      {
102           if (quarry( 1 ,i))
103          {
104               if (last ==- 1 ) last = i;
105              used = 1 ;
106          }
107           else
108          {
109               if (last !=- 1 )
110              {
111                  printf( " %c%d,%d%c  " ,last % 2 ? ' ( ' : ' [ ' ,last / 2 ,(i - 1 ) % 2 ? (i - 1 ) / 2 + 1 :(i - 1 ) / 2 ,(i - 1 ) % 2 ? ' ) ' : ' ] ' );
112                  last =- 1 ;
113              }
114          }
115      }
116       if ( ! used) printf( " empty set " );
117      printf( " \n " );
118  }
119  int  main()
120  {
121      
122       char  jud[ 5 ];
123      init( 0 , 65540 * 2 , 1 );
124       while (scanf( " %s " ,jud) != EOF)
125      {
126           char  str[ 128 ],type1,type2;
127           int  num1,num2;
128          scanf( " %s " ,str);
129          type1 = ( * str == ' ( ' );
130          type2 = (str[strlen(str) - 1 ] == ' ) ' );
131          str[strlen(str) - 1 ] = ' \0 ' ;
132          num1 = atoi(strtok(str + 1 , " , " ));
133          num2 = atoi(strtok(NULL, "   " ));
134           if (type1) num1 = num1 * 2 + 1 ;
135           else  num1 = num1 * 2 ;
136           if (type2) num2 = num2 * 2 - 1 ;
137           else  num2 = num2 * 2 ;
138           switch (jud[ 0 ])
139          {
140           case   ' U ' :
141               if (num1 <= num2) 
142                insert(num1,num2, 1 );
143               break ;
144           case   ' I ' :
145               if (num1 <= num2)
146              {
147                   if ( 0 <= num1 - 1 ) clear( 0 ,num1 - 1 , 1 );
148                   if (num2 + 1 <= 65540 * 2 ) clear(num2 + 1 , 65540 * 2 , 1 );
149              }
150               else  clear( 0 , 65540 * 2 , 1 );
151               break ;
152           case   ' D ' :
153               if (num1 <= num2)
154                clear(num1,num2, 1 );
155               break ;
156           case   ' C ' :
157               if (num1 <= num2)
158              {
159               if ( 0 <= num1 - 1 ) clear( 0 ,num1 - 1 , 1 );
160               if (num2 + 1 <= 65540 * 2 ) clear(num2 + 1 , 65540 * 2 , 1 );
161              turn(num1,num2, 1 );
162              }
163               else
164                  clear( 0 , 65540 * 2 , 1 );
165               break ;
166           case   ' S ' :
167               if (num1 <= num2)
168                  turn(num1,num2, 1 );
169               break ;
170          }
171      }
172      print();
173       return   0 ;
174  }

你可能感兴趣的:(pku 3225 区间 我对线段树延迟标记的一些理解)