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];//如果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

原文地址:https://www.cnblogs.com/00isok/p/9693880.html

时间: 2024-08-26 13:10:08

HDU 1540 Tunnel Warfare(区间合并)【线段树】的相关文章

hdu 1540 Tunnel Warfare(线段树)

题目链接:hdu 1540 Tunnel Warfare 题目大意:有连续的N个城镇,三种操作: D x:第x城镇被破坏 Q x:插叙第x城镇所在联通块有多少个城镇没有被破坏 R:修复最后一个被破坏的城镇 解题思路:线段树区间合并,每个城镇看成一个叶子节点,用一个vector记录破坏顺序.对于查询来说,每次只要判断是否在mid?R[lson(u)],mid+L[rson(u)]之间即可,否则即递归查询左右子树. #include <cstdio> #include <cstring>

hdu 1540 Tunnel Warfare【线段树】

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1540 题目大意:抗日战争时期,各村庄被一条地道连接着(村庄排在一条线上),有三种操作: 第一种:某村庄被敌军摧毁: 第二种:修复上一个被摧毁的村庄: 第三种:查询与该村庄直接或间接链接的村庄有多少个(包括自己): 此题用线段树做,每个节点包含该区间从左端开始有多大连续区间ls,从右端向左有多大连续区间rs,该区间的最大连续区间mas: 代码如下: #include <iostream> #incl

【区间合并线段树】BZOJ1593-安排住宿

[题目大意] 查询最左端的连续长度区间:或批量修改一些区间.[思路] 区间合并线段树……复习一下.POJ上有一样的题目,我居然还借用了别人的权限号去做BZOJ,简直愚昧到没朋友[笑cry] 处理方法以前的博文里有,这里有不赘述了. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cstdlib> 6 using

hdu 1540 Tunnel Warfare 线段树 单点更新,查询区间长度,区间合并

Tunnel Warfare Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1540 Description During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Gene

HDU 1540 Tunnel Warfare(线段树单点更新+区间合并)

Problem Description During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Generally speaking, villages connected by tunnels lay in a line. Except the two at the ends, every vill

HDU 1540 Tunnel Warfare 线段树区间合并

Tunnel Warfare 题意:D代表破坏村庄,R代表修复最后被破坏的那个村庄,Q代表询问包括x在内的最大连续区间是多少 思路:一个节点的最大连续区间由(左儿子的最大的连续区间,右儿子的最大连续区间,左儿子的最大连续右区间+右儿子的最大连续左区间)决定 所以线段树的节点应该维护当前节点的最大连续左区间,最大连续右区间,和最大连续区间. 注意更新的时候,如果左儿子全满,父亲节点的左连续区间还要加上右儿子的左区间.反之同理. 查询的时候,可以剪枝,如果是叶子,或为空,或满,则不用往下查询. 查询

HDU 1540 Tunnel Warfare 平衡树 / 线段树:单点更新,区间合并

Tunnel Warfare                                  Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Problem Description During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast

HDU 1540 Tunnel Warfare 线段树:单点更新,区间合并

Tunnel Warfare                                  Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Problem Description During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast

HDU 1540 Tunnel Warfare(线段树 区间合并 最大连续区间)

题意  有n个连在一起的地道  接下来有m个操作  D x 炸掉x号地道  炸掉后x所在的区间就不连续了  Q x 查询输出包括x的最大连续区间长度   R修复最后一个被炸的地道  注意输入R时可能并没有需要修复的地道 线段树的区间合并问题  线段树要维护3个信息 len  对应区间的最大连续长度 ll  对应区间最左端的一段连续长度 lr  对应区间最右端的一段连续长度 那么双亲节点的这些信息和孩子节点有什么关系呢  容易发现 双亲的len 是 左孩子的len 右孩子的len  左孩子的右端长