hdu1540-Tunnel Warfare-(线段树+二分)

Posted shoulinniao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu1540-Tunnel Warfare-(线段树+二分)相关的知识,希望对你有一定的参考价值。

题意:有n个村庄排成一列,相邻的村庄可以通信,炸毁则不可以通信,进行m个操作。3种操作,1.炸毁某村庄;2.修复上一个被炸毁的村庄;3.查询某个村庄能通信的村庄数(自己算一个)。

解题:求某个点左边扩散和右边扩散的区间和,没被炸毁就算1,炸毁则算0,用二分查找左边界和右边界,假设查询的点为x,则左边界是x-l+1=query(),右边界判断标准是r-x+1=query();两次二分log,查询query也是log,时间复杂度是O(n+m*log*log),限速2000ms,1600+ms,思路简单,勉强能过。

另外还有一个坑:一个村庄可以被多次炸毁,修复只需要一次就够了。

  1 #include<stdio.h>
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<math.h>
  6 #include<string>
  7 #include<map>
  8 #include<queue>
  9 #include<stack>
 10 #include<set>
 11 #define ll long long
 12 #define inf 0x3f3f3f3f
 13 using namespace std;
 14 
 15 int n,m;
 16 int a[50005];
 17 int sum[50005*4];
 18 stack<int>sta;
 19 
 20 void build(int l,int r,int rt)
 21 
 22     if(l==r)
 23     
 24         sum[rt]=a[l];
 25         return;
 26     
 27     int mid=(l+r)/2;
 28     build(l,mid,rt*2);
 29     build(mid+1,r,rt*2+1);
 30 
 31     sum[rt]=sum[rt*2]+sum[rt*2+1];
 32 
 33 
 34 void update(int p,int c,int l,int r,int rt)
 35 
 36     if(l==r)///到达叶节点,修改后返回
 37     
 38         sum[rt]=sum[rt]+c;
 39         return ;
 40     
 41     int mid=(l+r)/2;
 42     ///根据条件判断往左调用还是往右
 43     if(p<=mid) update(p,c,l, mid, rt*2);
 44     else     update(p,c,mid+1, r, rt*2+1);
 45     sum[rt] = sum[rt*2] + sum[rt*2+1];
 46 
 47 
 48 int query(int L,int R,int l,int r,int rt)
 49 
 50     if(L<=l&&r<=R)///在区间内,直接返回
 51         return sum[rt];
 52 
 53     int m=(l+r)/2;
 54 
 55     ///累计答案
 56     int ans=0;
 57     if(L<=m) ans=ans+query(L,R,l,m,rt*2);
 58     if(R>m)  ans=ans+query(L,R,m+1,r,rt*2+1);
 59 
 60     return ans;
 61 
 62 
 63 int main()
 64 
 65     while(scanf("%d%d",&n,&m)!=EOF)
 66     
 67         while(!sta.empty())
 68             sta.pop();
 69         set<int>se;
 70         for(int i=1;i<=n;i++)
 71             a[i]=1;
 72         build(1,n,1);
 73         char c;
 74         while(m--)
 75         
 76             getchar();
 77             scanf("%c",&c);
 78             int x;
 79             if(c==D)
 80             
 81                 scanf("%d",&x);
 82                 if(a[x]!=0)
 83                     update(x,-1,1,n,1);
 84                 a[x]=0;
 85                 sta.push(x);
 86             
 87             else if(c==R)
 88             
 89                 x=sta.top();
 90                 if( a[x]==0 );
 91                 else
 92                 
 93                     while( a[x]!=0 )
 94                     
 95                         sta.pop();
 96                         x = sta.top();
 97                     
 98                 
 99                 sta.pop();
100                 a[x]=1;
101                 update(x,1,1,n,1);
102             
103             else
104             
105                 int ans=0;
106                 scanf("%d",&x);
107 
108                 if(a[x]!=0)
109                 
110                     int l=1,r=x,res1=-1,res2=-1;
111                     while(l<=r)///往左找最大连通的村庄数
112                     
113                         int mid=(l+r)/2;
114                         if( query(mid,x,1,n,1)==x-mid+1 )///二分内往左找mid
115                         
116                             res1=mid;
117                             r=mid-1;
118 
119                         
120                         else///二分内往右找
121                         
122                             l=mid+1;
123                         
124                     
125                     l=x,r=n;
126                     while(l<=r)
127                     
128                         int mid=(l+r)/2;
129 
130                         if( query(x,mid,1,n,1)==mid-x+1 )
131                         
132                             res2=mid;
133                             l=mid+1;
134                         
135                         else
136                             r=mid-1;
137                     
138                     printf("%d\n",res2-res1+1);
139                 
140                 else
141                     printf("0\n");
142             
143         
144 
145     
146 
147     return 0;
148 
149 /**
150 5 12
151 D 3
152 D 2
153 D 1
154 D 1
155 D 2
156 R
157 R
158 R
159 Q 1
160 Q 2
161 Q 3
162 Q 4
163 */

 

以上是关于hdu1540-Tunnel Warfare-(线段树+二分)的主要内容,如果未能解决你的问题,请参考以下文章

hdu1540 Tunnel Warfare 线段树/树状数组

hdu--1540 Tunnel Warfare(线段树+区间合并)

线段树区间合并HDU1540-Tunnel Warfare

HDU 1540 Tunnel Warfare(线段树,单点更新,区间查询)

HDU 1540 Tunnel Warfare(线段树 区间合并)

HDU1540(Tunnel Warfare)