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

原题地址:https://vijos.org/p/1448

~~~~~~~~~~~~~~~~~~~~~~~~~~~分割线~~~~~~~~~~~~~~~~~~~~~~~~~~~

分析:

这道题是一个典型的区间问题,考虑到数据量较大,使用线段树完成这个操作。由于树的种类很多,不难想到用线段树暴力维护的方法。但是暴力维护一定会超时,那么这么解决这个问题呢?

这里介绍一种十分机智的想法——括号序列

假设有一个长度为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\n", ans);
95         }
96     }
97     return 0 ;
98 }

PS: 本题也可以用树状数组完成,代码量较少,容易实现。

(完)

时间: 2024-10-25 08:52:24

Vijos1448校门外的树 题解的相关文章

洛谷P1047校门外的树题解

摘要: 此题是一个模拟题,但需要注意的一点就是它的树是从数轴的0开始,所以我们也要从0开始,这样才能实现代码. 代码: #include<iostream> using namespace std; int s[100000]; int main() { int l,m,x,y,d=0; cin>>l>>m; for(int i=0; i<=l; i++) s[i]=1; for(int i=0; i<m; i++) { cin>>x>&g

题解-校门外的树

题目描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是 11 米.我们可以把马路看成一个数轴,马路的一端在数轴 00 的位置,另一端在 LL 的位置:数轴上的每个整数点,即 0,1,2,-,L0,1,2,-,L ,都种有一棵树. 由于马路上有一些区域要用来建地铁.这些区域用它们在数轴上的起始点和终止点表示.已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分.现在要把这些区域中的树(包括区域端点处的两棵树)移走.你的任务是计算将这些树都移走后,马路上还有多少棵

Tyvj - 1286 - 校门外的树2

描述 Description 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L,都种有一棵树. 由于马路上有一些区域要用来建地铁.这些区域用它们在数轴上的起始点和终止点表示.已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分.现在要把这些区域中的树(包括区域端点处的两棵树)移走.你的任务是计算将这些树都移走后,马路上还有多少棵树. 输入格式 I

C语言 &#183; 校门外的树

算法提高 校门外的树 时间限制:1.0s   内存限制:256.0MB 问题描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,--,L,都种有一棵树. 由于马路上有一些区域要用来建地铁.这些区域用它们在数轴上的起始点和终止点表示.已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分.现在要把这些区域中的树(包括区域端点处的两棵树)移走.你的任务是计算

P1047 校门外的树

P1047 校门外的树 题目描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L,都种有一棵树. 由于马路上有一些区域要用来建地铁.这些区域用它们在数轴上的起始点和终止点表示.已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分.现在要把这些区域中的树(包括区域端点处的两棵树)移走.你的任务是计算将这些树都移走后,马路上还有多少棵树. 输入输出

TyvjOJ题目 P1473 校门外的树3(线段树区间染色种类数不覆盖)

P1473 校门外的树3 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的-- 如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作: K=1,读入l,r表示在l~r之间种上的一种树 K=2,读入l,r表示询问l~r之间能见到多少种树 (l,r>0) 输入格式 第一行n,m表示道路总长为n,共有m个操作 接下来m行为m个操作 输出格式 对于每个k=

NOIP200502校门外的树

试题描述     某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L,都种有一棵树.由于马路上有一些区域要用来建地铁.这些区域用它们在数轴上的起始点和终止点表示.已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分.现在要把这些区域中的树(包括区域端点处的两棵树)移走.你的任务是计算将这些树都移走后,马路上还有多少棵树. 输入 第一行有两个整数L和

【蓝桥杯】校门外的树

原文地址:http://leihuang.net/2014/05/19/List-Interviews/ 单链表的一些常见面试题汇总 单链表反转/逆序 求单链表倒数第N个数 找到单链表的中间结点 如何判断链表是否有环的存在 单链表建环,无环链表变有环 如何知道环的长度? 如何找出环的连接点在哪里? 删除单链表中的重复元素 下面我先简单叙述一下每道题的思路,然后把实现的程序一起贴出来,不会讲得太细,我觉得只要有了思路之后,接下来的难点就是语言上的一些细节问题了,这个不自己去实现,听别人讲是体会不到

Vijos P1448 校门外的树【多解,线段树,树状数组,括号序列法+暴力优化】

校门外的树 描述 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的…… 如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作: 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输出一个答案 样例1 样例输入1 5 4 1 1