• HDU 1540 Tunnel Warfare(经典)(区间合并)【线段树】


    <题目链接>

    题目大意:

    一个长度为n的线段,下面m个操作

    D x 表示将单元x毁掉

    R  表示修复最后毁坏的那个单元

    Q x  询问这个单元以及它周围有多少个连续的单元,如果它本身已经被毁坏了就是0。

    解题分析:

    用线段树求指定点所在的最长连续区间,属于线段树区间合并类型的题,线段树的每个节点需要维护三个值,分别是对应区间的最长连续区间长度,对应区间最长连续区间前缀,对应区间最长连续后缀,然后就是在每次update之后都维护一下这三个值就行。并且注意一下query 时的操作。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 #define Lson rt<<1,l,mid
     7 #define Rson rt<<1|1,mid+1,r
     8 const int N=50000+4;
     9 int len[N<<2],llen[N<<2],rlen[N<<2];
    10 int n,m;
    11 
    12 void Pushup(int rt,int length){    //更新维护每个节点的三个值
    13     llen[rt]=llen[rt<<1];   //首先当前节点的最长连续前缀==左子节点的最长连续前缀     
    14     rlen[rt]=rlen[rt<<1|1];
    15     /*-- 进一步更新 --*/   
    16     if(llen[rt<<1]==(length-(length>>1)))llen[rt]+=llen[rt<<1|1]; //如果左子节点的最长连续前缀为整个左子区间,那么本节点的前缀还要加上右子区间的最长前缀
    17     if(rlen[rt<<1|1]==(length>>1))rlen[rt]+=rlen[rt<<1];          //同理
    18     /*-- 最终更新本节点的最长连续长度  --*/
    19     len[rt]=max(max(len[rt<<1],len[rt<<1|1]),rlen[rt<<1]+llen[rt<<1|1]); 
    20 }
    21 
    22 void build(int rt,int l,int r){
    23     if(l==r){
    24         len[rt]=llen[rt]=rlen[rt]=1;
    25         return;
    26     }
    27     int mid=(l+r)>>1;
    28     build(Lson);
    29     build(Rson);
    30     Pushup(rt,r-l+1);
    31 }
    32 
    33 void update(int rt,int l,int r,int loc,int c){   //单点更新
    34     if(l==r){
    35         len[rt]=llen[rt]=rlen[rt]=c; 
    36         return;
    37     }
    38     int mid=(l+r)>>1;
    39     if(loc<=mid)update(Lson,loc,c);
    40     if(loc>mid)update(Rson,loc,c);
    41     Pushup(rt,r-l+1);
    42 }
    43 
    44 int query(int rt,int l,int r,int loc){
    45     if(l==r)return len[rt];
    46     int mid=(l+r)>>1;
    47     if(loc<=mid){
    48         if(loc+rlen[rt<<1]>mid)return rlen[rt<<1]+llen[rt<<1|1]; //如果loc在左子区间的最长后缀和右子区间的最长前缀中,直接输出这两个前后缀之和即可
    49         else return query(Lson,loc);  //否则的话,继续向左子节点查询
    50     }
    51     else{
    52         if(mid+llen[rt<<1|1]>=loc)return rlen[rt<<1]+llen[rt<<1|1];//因为右子区间是(mid,r]左开区间,所以这里判断loc是否在右子区间的前缀的范围内用的是 ">="
    53         else return query(Rson,loc);
    54     }
    55 }
    56 
    57 int main(){
    58     while(scanf("%d %d",&n,&m)!=EOF){
    59         build(1,1,n);
    60         int tot=0,stk[N+10]; //stk模拟栈
    61         while(m--){
    62             char str[10];
    63             scanf("%s",str);
    64             if(str[0]=='D'){
    65                 int cal;scanf("%d",&cal);
    66                 stk[++tot]=cal;
    67                 update(1,1,n,cal,0);
    68             }
    69             else if(str[0]=='R'){
    70                 int cal=stk[tot--];
    71                 update(1,1,n,cal,1);
    72             }
    73             else{
    74                 int cal;scanf("%d",&cal);
    75                 printf("%d
    ",query(1,1,n,cal));
    76             }
    77         }
    78     }
    79     return 0;
    80 }

    2018-09-23

  • 相关阅读:
    C#开发ActiveX控件并应用于网页
    C#编写ActiveX控件
    WPF Step By Step 系列5-Prism框架在项目中使用
    WPF Step By Step4- 自定义模板
    WPF Step By Step3- 控件介绍
    WPF Step By Step2 -基础知识介绍
    WPF Step By Step 系列1
    斑马打印机设定值取值优先级顺序
    WPF资料汇总
    linux(centos8):使用cgroups做资源限制
  • 原文地址:https://www.cnblogs.com/00isok/p/9693880.html
Copyright © 2020-2023  润新知