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 */