zoukankan      html  css  js  c++  java
  • CodeForces

    题目

    晚上有n个亮着的灯泡,标号从1到n。

    现在存在2种操作,如下:

    • 操作1,关掉标号 [l,r] 区间的灯
    • 操作2,打开标号 [l,r] 区间的灯

    下面有q次询问,每次询问执行其中一种操作,询问格式,l,r,k,k为执行操作种类。对于每次询问回答当前开着的灯的数量。

    Input

    单组输入,第一行包含一个整数n,第二行一个整数q(1≤n≤10^9,1≤q≤3·10^5)

    接下来q行每行3个整数表示询问,l,r,k(1 ≤ l ≤ r ≤ n, 1 ≤ k ≤ 2).

    Output

    对于每次询问回答一个整数占一行表示答案。

    Example

    Input
    4
    6
    1 2 1
    3 4 1
    2 3 2
    1 3 2
    2 4 1
    1 4 2
    Output
    2
    0
    2
    3
    1
    4

    题解:

    因为线段树要开4倍空间。然而面对庞大的数据我们开maxn<<2的空间是肯定开不下的。

    这时候就要用到动态开点线段树来节省空间了。( 或者离散化 )

    动态开点也就是当用到那个节点的时候才给它分配空间,否则就不分配,就比如像这一道题n的大小是1e9,那么静态开点肯定炸空间了,,,但是你发现他询问的区间也就3e5个,可见用到的区间还是少数,所以每当用到一个区间我们再给他分配空间

    代码:

     1 /*
     2 动态开点线段树
     3 */
     4 #include<stdio.h>
     5 #include<string.h>
     6 #include<iostream>
     7 #include<algorithm>
     8 #include<queue>
     9 #include<vector>
    10 using namespace std;
    11 const int maxn=3e5+10;
    12 const int INF=0x3f3f3f3f;
    13 typedef long long ll;
    14 struct Node
    15 {
    16     int l,r,sum,lazy;
    17     Node()
    18     {
    19         l=0,r=0,sum=0,lazy=0;
    20     }
    21 } node[maxn*50];
    22 int cnt=1;  //开点的数量
    23 void pushdown(int l,int r,int k) //k是父节点在数组中的序号
    24 {
    25     int mid=(l+r)>>1;
    26     if(l!=r)
    27     {
    28         if(!node[k].l) node[k].l=++cnt;
    29         if(!node[k].r) node[k].r=++cnt;
    30 
    31         if(node[k].lazy==2)
    32         {
    33             node[node[k].l].sum=node[node[k].r].sum=0;
    34         }
    35         else
    36         {
    37             node[node[k].l].sum=mid-l+1;
    38             node[node[k].r].sum=r-mid;
    39         }
    40         node[node[k].l].lazy=node[k].lazy;
    41         node[node[k].r].lazy=node[k].lazy;
    42     }
    43     node[k].lazy=0;
    44 }
    45 //往线段树里面插入一个区间[L,R]
    46 void Insert(int l,int r,int &k,int L,int R,int p)
    47 {
    48     if(!k) k=++cnt;  //这个k也就相当于我们要对node[k]这个节点进行操作
    49     //node[1]是根节点,因为我们这是动态开点,所以没有开点的节点都是初始值0
    50     if(l>=L && r<=R)  //如果满足这个条件也就不需要pushdown,因为我们不需要下面节点就可以得到[l,r]区间内的答案
    51     {
    52         if(p==2) node[k].sum=0;
    53         else node[k].sum=r-l+1;
    54         node[k].lazy=p;
    55         return;
    56     }
    57     //如果不满足上面那个判断,那么我们就要递归进入k的左右子节点,这个时候,你要保证左右子点都已经被修改好了
    58     //即,懒惰标记lazy是0
    59     if(node[k].lazy) pushdown(l,r,k);
    60     int mid=(l+r)>>1;
    61     if (mid>=L) Insert(l,mid,node[k].l,L,R,p);
    62     if (mid<R) Insert(mid+1,r,node[k].r,L,R,p);
    63     node[k].sum=node[node[k].l].sum+node[node[k].r].sum;
    64 }
    65 int main()
    66 {
    67     //printf("%d %d
    ",node[1].l,node[1].r);
    68     int n,q;
    69     scanf("%d %d",&n,&q);
    70     int k=1;
    71     for (int i=1; i<=q; i++)
    72     {
    73         int l,r,p;
    74         scanf("%d %d %d",&l,&r,&p);
    75         Insert(1,n,k,l,r,p);
    76         printf("%d
    ",n-node[1].sum);
    77     }
    78     return 0;
    79 }
  • 相关阅读:
    移动传感器扫描覆盖
    最小生成树
    什么是壳 脱壳篇01
    最小生成树
    最小生成树
    最小生成树
    最小生成树
    最小生成树
    普里姆算法
    普里姆算法
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/12621431.html
Copyright © 2011-2022 走看看