• 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
    " , tr[ 1 ].Cnt ) ;
    101         }
    102         fclose(stdin);
    103         fclose(stdout);
    104         Never Explode ;
    105 }
    Weed

    NOIP_RP++;

    2016-10-07 20:28:07

    (完)

  • 相关阅读:
    设置ActiveMQ的访问密码
    Java NIO SocketChannel套接字通道
    Java 8 基础API的一些小的该进
    Java 8 异常该进
    Java NIO Channel to Channel Transfers通道传输接口
    Java NIO Scatter / Gather
    mysql分表经验总结
    Java 8 Optional类深度解析(转)
    Java 8 文件操作(转)
    使用 Java8 Optional 的正确姿势(转)
  • 原文地址:https://www.cnblogs.com/shadowland/p/5935772.html
Copyright © 2020-2023  润新知