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\n",query(1,1,n,cal));
76             }
77         }
78     }
79     return 0;
80 }

 

 

2018-09-23

posted @ 2018-09-23 21:49  悠悠呦~  阅读(213)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end