20161003 NOIP 模拟赛 T2 解题报告

Weed

  duyege的电脑上面已经长草了,经过辨认上面有金坷垃的痕迹。

  为了查出真相,duyege 准备修好电脑之后再进行一次金坷垃的模拟实验。

  电脑上面有若干层金坷垃,每次只能在上面撒上一层高度为 vi 的金坷垃,或者除掉最 新 vi 层(不是量)撒的金坷垃。如果上面只留有不足 vi 层金坷垃,那么就相当于电脑上 面没有金坷垃了。

  duyege 非常严谨,一开始先给你 m 个上述操作要你依次完成。然后又对实验步骤进行 了 q 次更改,每次更改都会改变其中一个操作为另外一个操作。每次修改之后都会询问最 终金坷垃的量有多少。

  输入第一行为两个正整数 m、q,接下来 m 行每行 2 个整数 k、vi。k 为 0 时撒金坷垃, 为 1 时除金坷垃。接下来 q 行每行 3 个整数 ci、k、vi,ci 代表被更改的操作是第 ci 个, 后面 2 个数描述更改为这样的操作。 输出 q 行代表每次金坷垃的量为多少

  对于 30%的数据,m<=1000,q<=1000.

  对于另外 20%的数据,每次 k=1 时都会将金坷垃清空。

  对于 100%的数据,m<=2*10^5,q<=2*10^5,vi<=10^4.

 

——————————————分割线——————————————

分析:

  ( 30分 )这道题朴素想法是每次对某个操作修改,然后依次算到最后一个元素。

  ( 100分 )朴素的想法在逐个计算上耗时太多,这时我们需要一种数据结构,能够对某个操作修改,又能够对某一段查询,那么不难想到线段树。

我们需要维护三个信息,即当前区间中操作的金坷垃数量,层数,以及需要删去更左边操作的层数。

显然左边的删除操作不会影响之后的操作,那么我们只需要对每个节点进行结算,统计即可。

下面代码的Push_up函数比较难懂,特此注释。

  1 #include "bits/stdc++.h"
  2 #define Never return 
  3 #define Explode 0 
  4  
  5 using namespace std ;
  6 struct SegTree { int l , r , Add , Cnt , Del ;};
  7 const int maxN = 2e5 + 100 ;
  8 
  9 SegTree tr[ maxN << 2 ] ;
 10 int arr[ maxN ] ;
 11 bool op[ maxN ] ;
 12 
 13 int INPUT ( ) {
 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 << 1 ) + ( x << 3) + ch - '0' ; ch = getchar( ) ; }
 17         return x * f ;
 18 }
 19 
 20 int Query_Tree ( const int i , const int Target ) {
 21         if ( Target == tr[ i << 1 | 1 ].Add ) {
 22                 return tr[ i ].Cnt - tr[ i << 1 | 1 ].Cnt ;
 23         }
 24         else if ( Target < tr[ i << 1 | 1 ].Add ) {
 25                 return tr[ i ].Cnt - tr[ i << 1 | 1 ].Cnt + Query_Tree ( i << 1 | 1 , Target ) ;
 26         }
 27         else {
 28                 return Query_Tree ( i << 1 , Target - tr[ i << 1 | 1 ].Add + tr[ i << 1 | 1 ].Del ) ;
 29         }
 30 }
 31 
 32 void Push_up ( const int i ) {
 33         int lchild = i << 1 ;
 34         int rchild = lchild + 1 ;
 35         if ( tr[ rchild ].Del >= tr[ lchild ].Add ) {//右区间 删除数大于等于左边层数 
 36                 tr[ i ].Del = tr[ lchild ].Del + tr[ rchild ].Del - tr[ lchild ].Add ;
 37                 tr[ i ].Add = tr[ rchild ].Add ;
 38                 tr[ i ].Cnt = tr[ rchild ].Cnt ;
 39         }
 40         else if ( !tr[ rchild ].Del ) {//右区间没有删除 
 41                 tr[ i ].Add = tr[ lchild ].Add + tr[ rchild ].Add ;
 42                 tr[ i ].Cnt = tr[ lchild ].Cnt + tr[ rchild ].Cnt ;
 43                 tr[ i ].Del = tr[ lchild ].Del ;
 44         }
 45         else {//右边无法全部删去左边 
 46                 tr[ i ].Del = tr[ lchild ].Del ;
 47                 tr[ i ].Add = tr[ lchild ].Add + tr[ rchild ].Add - tr[ rchild ].Del ;
 48                 tr[ i ].Cnt = tr[ rchild ].Cnt + Query_Tree ( lchild , tr[ rchild ].Del ) ;
 49         }
 50 }
 51 void Build_Tree ( const int x , const int y , const int i ) {
 52         tr[ i ].l = x ; 
 53         tr[ i ].r = y ;
 54         if ( x == y ) {
 55                 if ( op[ x ] ) tr[ i ].Del = arr[ x ] ;
 56                 else if ( !op[ x ] ) {
 57                         tr[ i ].Add = 1 ;
 58                         tr[ i ].Cnt = arr[ x ] ;
 59                 }
 60         }
 61         else {
 62                 int mid = ( tr[ i ].l + tr[ i ].r ) >> 1 ;
 63                 Build_Tree ( x , mid , i<<1 ) ;
 64                 Build_Tree ( mid + 1 , y , i<<1|1 ) ;
 65                 Push_up ( i ) ;
 66         }
 67         return ;
 68 }
 69 
 70 void Update_Tree ( const int i , const int Target ) {
 71         if ( tr[ i ].l == tr[ i ].r ) {
 72                 tr[ i ].Add = tr[ i ].Cnt = tr[ i ].Del = 0 ;
 73                 if ( INPUT ( ) ) {
 74                         tr[ i ].Del = INPUT( ) ;
 75                 }
 76                 else {
 77                         tr[ i ].Cnt = INPUT ( ) ;
 78                         tr[ i ].Add = 1 ;
 79                 }
 80         }
 81         else {
 82                 int mid = ( tr[ i ].l + tr[ i ].r ) >> 1 ;
 83                 if ( Target > mid ) Update_Tree ( i << 1 | 1 , Target ) ;
 84                 else if( Target <= mid ) Update_Tree ( i << 1 , Target ) ;
 85                 Push_up ( i ) ;
 86         }
 87         return ;
 88 }
 89 
 90 int main ( ) {
 91         int N , Q ;
 92         freopen("weed.in", "r", stdin);
 93         freopen("weed.out", "w", stdout);
 94         scanf ( "%d%d" , &N , &Q ) ;
 95         for ( int i=1 ; i<=N ; ++i ) scanf ("%d%d" , op + i , arr + i ) ;
 96         Build_Tree ( 1 , N , 1 ) ;
 97         while ( Q-- ) {
 98                 int tmp = INPUT ( ) ;
 99                 Update_Tree ( 1 , tmp ) ;
100                 printf ( "%d\n" , tr[ 1 ].Cnt ) ;
101         }
102         fclose(stdin);
103         fclose(stdout);
104         Never Explode ;
105 }
Weed

NOIP_RP++;

2016-10-07 20:28:07

(完)

posted @ 2016-10-07 12:48  SHHHS  阅读(381)  评论(0编辑  收藏  举报