线段树的应用一中模拟lites

2018-07-16 02:36:06来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

跟昨天那个自己写的,没有按照模板来的一看风格就不相类似,今天模拟赛的时候就是用的我的那个自己YY的代码,才拿了10分。个人认为关键的问题应该在于对于数据的处理太过繁琐了,所以回来之后,就拿了大佬的程序对照着改。在这里不得不吐槽一下c++的读入,cin40分,scanf满分。还是模板的线段树比较清晰,决定以后就用这种了。

开关灯
源文件:    lites.cpp/.c/.pas
输入文件:    lites.in
输出文件:    lites.out
时限:        1s
空间:     256M
【题目描述】
小Y尝试通过和奶牛们玩益智玩具来保持他的奶牛们思维敏捷,其中一个大型玩具是牛栏中的灯。
N (2<= N <= 100,000) 头奶牛中的每一头被连续的编号为1..N, 站在一个彩色的灯下面。刚到傍晚的时候, 所有的灯都是关闭的。奶牛们通过N个按钮来控制灯的开关,按第i个按钮可以改变第i个灯的状态。
奶牛们执行M (1<= M <= 100,000)条指令, 每个指令都是两个整数中的一个(0<= 指令号<= 1)。
第1种指令(用0表示)包含两个数字S_i和E_i (1<= S_i<= E_i<= N), 它们表示起始开关和终止开关。奶牛们只需要把从S_i到E_i之间的按钮都按一次, 就可以完成这个指令。
第2种指令(用1表示)同样包含两个数字S_i和E_i (1<= S_i<= E_i<= N), 不过这种指令是询问从S_i到E_i之间的灯有多少是亮着的。
请你帮助小Y确保他的奶牛们可以得到正确的答案。
【输入格式】
第 1 行: 用空格隔开的两个整数N和M。
第 2..M+1 行: 每行表示一个操作, 有三个用空格分开的整数: 指令号, S_i 和 E_i。
【输出格式】
对于每一次询问, 输出一行表示询问的结果。
【输入样例】
4 5
0 1 2
0 2 4
1 2 3
0 2 4
1 1 4
【输出样例】
1
2
【样例解释】
一共有4盏灯,5个指令。下面是执行的情况:
    灯
            1 2 3 4
Init:     O OOOO = 关* =0 1 2 ->  * * O O改变灯 12 的状态
  0 2 4 ->  * O * *
  1 2 3 ->  1        输出在2..3的范围内有多少灯是亮的
  0 2 4 ->  * * O O改变灯 2 ,34 的状态
  1 1 4 ->  2        输出在1..4的范围内有多少灯是亮的
【数据规模】
对于40%的数据满足:1<=N,M<=10000;
对于100%的数据满足: 1<=N,M<=100000

(很明显的线段树,开始我还很开心,因为昨天刚调出来,以为要AC了)。

下面是自己改的代码。

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 struct node{
 4     int l,r,dat,lazy;
 5 }shu[400010];//结构体,中间的任何一个单独成为一个数组都是可以的,其实没有什么高大上的,只是看起来比较高逼格而已。
 6 int n,m,a,b,c,ans;//个人建议多设全局变量,Pascal的优良传统,比较方便,不容易错。
 7 void build_tree(int x,int y,int z){//建树,和昨天我的代码是一样的(不对,是今天)。
 8     shu[x].l=y;
 9     shu[x].r=z;
10     if (y==z) return;
11     int o=(y+z)/2; 
12     build_tree(x*2,y,o);
13     build_tree(x*2+1,o+1,z);
14 }
15 void caozuo(int x){//操作,为什么要单独在一个过程中呢?因为下面两段都要用到,更方便编程思路更清晰。
16     if (shu[x].lazy){//开灯的时候改变。也可以用bool数组。
17         shu[x*2].dat=(shu[x*2].r-shu[x*2].l+1)-shu[x*2].dat;//这是因为一部分是开的,那么改变了之后,另一部分就是开的,这一部分是关的。
18         shu[x*2+1].dat=(shu[x*2+1].r-shu[x*2+1].l+1)-shu[x*2+1].dat;
19         if (shu[x*2].lazy) shu[x*2].lazy=0;
20         else shu[x*2].lazy=1;
21         if (shu[x*2+1].lazy) shu[x*2+1].lazy=0;
22         else shu[x*2+1].lazy=1;
23         shu[x].lazy=0;//处理完了,lazy标记还原。
24     }
25 }
26 void add_tree(int x){
27     if (shu[x].l>=b&&shu[x].r<=c){
28         shu[x].dat=(shu[x].r-shu[x].l+1)-shu[x].dat;//两遍开就是关
29         if (shu[x].lazy) shu[x].lazy=0;
30         else shu[x].lazy=1;
31         return;
32     }
33     caozuo(x);
34     int o=(shu[x].l+shu[x].r)/2;
35     if(b<=o) add_tree(x*2);//如果中间数比要改变区间最左边大或相等,查找左子树。
36     if(c>o) add_tree(x*2+1);//如果中间数比要改变区间最右边小,查找右子树。
37     shu[x].dat=shu[x*2].dat+shu[x*2+1].dat;//更新父节点
38 }
39 void find_tree(int x){//查找区间和。
40     if (shu[x].l>=b&&shu[x].r<=c){//在要查区间内就加上对应区间和,不用往下找,因为子结点的区间在父节点的区间之内,不应该重复。
41         ans=ans+shu[x].dat;
42         return;
43     }
44     caozuo(x);
45     int o=(shu[x].l+shu[x].r)/2;
46     if(b<=o) find_tree(x*2);
47     if(c>o) find_tree(x*2+1);
48     return;
49 }
50 int main(){
51     scanf("%d%d",&n,&m);
52     build_tree(1,1,n);
53     for (int i=1;i<=m;i++){
54         scanf("%d%d%d",&a,&b,&c);
55         if (a==0){
56             add_tree(1);
57         }
58         else {
59             ans=0;
60             find_tree(1);
61             printf("%d\n",ans);
62         }
63     }
64     return 0;
65 }

 难点是如何处理开着灯的数量,这就要求我们在更新的过程中,对lazy进行处理。

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:c++教程

下一篇:CBCGPImage的GetSize的问题及解决方法