zoukankan      html  css  js  c++  java
  • Vijos1448校门外的树 题解

    Vijos1448校门外的树 题解

    描述:
    校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的……
    如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作:
    K=1,K=1,读入l、r表示在区间[l,r]中种上一种树,每次操作种的树的种类都不同
    K=2,读入l,r表示询问l~r之间能见到多少种树
    (l,r>0)
     
    输入格式:
    第一行n,m表示道路总长为n,共有m个操作
    接下来m行为m个操作
     
    输出格式:
    对于每个k=2输出一个答案
     
    样例输入:
    5 4
    1 1 3
    2 2 5
    1 2 4
    2 3 5
     
    样例输出:
    1
    2
     
    数据范围:
    20%的数据保证,n,m<=100
    60%的数据保证,n <=1000,m<=50000
    100%的数据保证,n,m<=50000
     
     
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~分割线~~~~~~~~~~~~~~~~~~~~~~~~~~~
     
    分析:
    这道题是一个典型的区间问题,考虑到数据量较大,使用线段树完成这个操作。由于树的种类很多,不难想到用线段树暴力维护的方法。但是暴力维护一定会超时,那么这么解决这个问题呢?
    这里介绍一种十分机智的想法——括号序列
    假设有一个长度为10的数轴,我们要将区间[ 2 , 5 ]中种树,这时,我们将 2 处放一个左括号 " ( "  ,5处放一个 " )"  ,表示区间 [ 2 , 5 ]种了树。
    查询某个区间树的种类,如区间[ 3 , 10],只需统计10之前(包括10)有多少个‘(’,统计3之前有多少个‘)’,(不包括3)。  
    如下图所示:

    以上就是括号序列的过程。简单的说,就是更新区间[a,b]时,点a记录左括号数,点b记录右括号数,查询区间[a,b]时,即为b之前(包括b)的左括号数-a之前的右括号数。
     
    下面贴注释代码:
     
     1 #include "bits/stdc++.h"
     2 #define maxN 50010
     3 
     4 using namespace std ;
     5 typedef long long QAQ ;
     6 
     7 struct Tree
     8 {
     9     int l , r ;
    10     QAQ liml , limr ;//左括号右括号
    11 };
    12 
    13 Tree tr[maxN << 2];
    14 
    15 void Build_Tree ( int x , int y , int i )//建树
    16 {
    17     tr[i].l = x ;
    18     tr[i].r = y ;
    19     if( x == y )return ;
    20     else
    21     {
    22         QAQ mid = (tr[i].l + tr[i].r) >> 1 ;
    23         Build_Tree ( x , mid , i << 1);
    24         Build_Tree ( mid + 1 , y , i << 1 | 1);
    25         return ;
    26     }
    27 }
    28 
    29 void Update_left ( int w , int i )
    30 {
    31     if( w == tr[i].l && w == tr[i].r )tr[i].liml++;//找到目标节点
    32     else
    33     {
    34         QAQ mid = (tr[i].l + tr[i].r) >> 1 ;
    35         if( w > mid )Update_left( w , i << 1 | 1);//找右儿子
    36         else if( w <= mid)Update_left( w , i << 1 );//找左儿子
    37         tr[i].liml = tr[i << 1].liml + tr[i << 1 | 1].liml ;//回溯更新
    38     }
    39 }
    40 
    41 void Update_right ( int w , int i )//同Update_left
    42 {
    43     if( w == tr[i].l && w == tr[i].r )tr[i].limr++;
    44     else
    45     {
    46         QAQ mid = (tr[i].l + tr[i].r) >> 1 ;
    47         if( w > mid )Update_right( w , i << 1 | 1);
    48         else if( w <= mid)Update_right( w , i << 1 );
    49         tr[i].limr = tr[i << 1].limr + tr[i << 1 | 1].limr ;
    50     }
    51 }
    52 
    53 QAQ Query_left ( int q , int w , int i )//同Query_right
    54 {
    55     if( q <= tr[i].l && w >= tr[i].r )return tr[i].liml ;
    56     else
    57     {
    58         QAQ mid = (tr[i].l + tr[i].r) >> 1 ;
    59         if ( q > mid )return Query_left ( q , w , i << 1 | 1);
    60         else if ( w <= mid ) return Query_left ( q , w , i << 1);
    61         else return Query_left ( q , w , i << 1 | 1) + Query_left ( q , w , i << 1);
    62     }
    63 }
    64 
    65 QAQ Query_right ( int q , int w , int i )
    66 {
    67     if( q <= tr[i].l && w >= tr[i].r )return tr[i].limr ;//找到目标区间直接返回
    68     else
    69     {
    70         QAQ mid = (tr[i].l + tr[i].r) >> 1 ;
    71         if ( q > mid )return Query_right ( q , w , i << 1 | 1);//找右儿子
    72         else if ( w <= mid ) return Query_right ( q , w , i << 1);//找左儿子
    73         else return Query_right ( q , w , i << 1 | 1) + Query_right ( q , w , i << 1);//左右儿子都查找
    74     }
    75 }
    76 
    77 int main()
    78 {
    79     int N, M, op, ll, rr ;
    80     scanf("%d %d", &N, &M);
    81     Build_Tree ( 1 , N , 1 ) ;//建树
    82     while(M--)
    83     {
    84         scanf("%d%d%d", &op, &ll, &rr);
    85         if( op == 1 )
    86         {
    87             Update_left ( ll , 1);//添加左括号
    88             Update_right ( rr , 1 );//添加右括号
    89         }
    90         else
    91         {
    92             QAQ ans = Query_left( 1 , rr , 1);
    93             if (ll != 1)ans -= Query_right(1 , ll - 1 , 1);//当ll不等于1时再相减,否则栈会炸
    94             printf("%I64d
    ", ans);
    95         }
    96     }
    97     return 0 ;
    98 }
     PS: 本题也可以用树状数组完成,代码量较少,容易实现。
     
     (完)
     
  • 相关阅读:
    Java如何编写自动售票机程序
    install windows service
    redis SERVER INSTALL WINDOWS SERVICE
    上传文件
    This problem will occur when running in 64 bit mode with the 32 bit Oracle client components installed.
    解决Uploadify上传控件加载导致的GET 404 Not Found问题
    OracleServiceORCL服务不见了怎么办
    Access to the temp directory is denied. Identity 'NT AUTHORITYNETWORK SERVICE' under which XmlSerializer is running does not have sufficient permiss
    MSSQL Server 2008 数据库安装失败
    数据库数据导出成XML文件
  • 原文地址:https://www.cnblogs.com/shadowland/p/5870395.html
Copyright © 2011-2022 走看看