Tunnel Warfare HDU - 1540 线段树之连通区间查询(巧用最大值,最小值)

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 village was directly connected with two neighboring ones.

Frequently the invaders launched attack on some of the villages and destroyed the parts of tunnels in them. The Eighth Route Army commanders requested the latest connection state of the tunnels and villages. If some villages are severely isolated, restoration of connection must be done immediately! 

InputThe first line of the input contains two positive integers n and m (n, m ≤ 50,000) indicating the number of villages and events. Each of the next m lines describes an event. 

There are three different events described in different format shown below: 

D x: The x-th village was destroyed. 

Q x: The Army commands requested the number of villages that x-th village was directly or indirectly connected with including itself. 

R: The village destroyed last was rebuilt. 
OutputOutput the answer to each of the Army commanders’ request in order on a separate line.
Sample Input

7 9
D 3
D 6
D 5
Q 4
Q 5
R
Q 4
R
Q 4

Sample Output

1
0
2
4

题意:有一排相互连接的村庄,给定三个操作,D表示摧毁第x个村庄,R表示修复上一个被摧毁的村庄,Q表示查询于第x个
村庄相连接的村庄数量,注意输入数据有多组。

思路:可以看出这个题时线段树的模板题,像摧毁操作和恢复操作都可以用线段树来轻松实现,但比较难的是查询连通的数量。首先我们可以转换一下思路,求这个连通的数量最简单的不就是找与这个村庄相连的最右边的和最左边的村庄吗,
转换一下就是求这个村庄于起点1之间的一个最大值和这个个村庄与终点m之间的一个最小值。然后就有了一个奇妙的想法,假如我们给定所有村庄的最小值为一个比较大的数(比如m+1),然后最大值为0,在摧毁村庄时把这两个值变为它自
己的编号,这样求连通区间的最右边就是被摧毁的最小值,最左边就是被摧毁的最大值啦。这样连通的问题就被解决了,最后要注意mi-ma+1,和恢复的是上一个被摧毁的村庄,应当开一个数组保存被摧毁的顺序。

代码:
  1 #include <cstdio>
  2 #include <fstream>
  3 #include <algorithm>
  4 #include <cmath>
  5 #include <deque>
  6 #include <vector>
  7 #include <queue>
  8 #include <string>
  9 #include <cstring>
 10 #include <map>
 11 #include <stack>
 12 #include <set>
 13 #include <sstream>
 14 #include <iostream>
 15 #define mod 998244353
 16 #define eps 1e-6
 17 #define ll long long
 18 #define INF 0x3f3f3f3f
 19 using namespace std;
 20 
 21 const int maxn=500000;
 22 int m,n;
 23 struct node
 24 {
 25     //l表示左边,r表示右边
 26     int li,ri;
 27     int mi,ma;
 28 };
 29 node no[maxn];
 30 //初始化,k表示当前节点的编号,l表示当前区间的左边界,
 31 void build(int k,int l,int r)
 32 {
 33     no[k].li=l;
 34     no[k].ri=r;
 35     //如果递归到最低点
 36     if(l==r)
 37     {
 38         no[k].mi=m+1;
 39         no[k].ma=0;
 40         return ;
 41     }
 42     //对半分
 43     int mid=(l+r)/2;
 44     //递归到左线段
 45     build(k*2,l,mid);
 46     //递归到右线段
 47     build(k*2+1,mid+1,r);
 48     //更新当前节点的值
 49     no[k].mi=min(no[k*2].mi,no[k*2+1].mi);
 50     no[k].ma=max(no[k*2].ma,no[k*2+1].ma);
 51 }
 52 
 53 //单点修改,指定坐标x的值修改为y
 54 void singlemodify(int k,int x,int y)
 55 {
 56     if(no[k].li==no[k].ri)
 57     {
 58         no[k].mi=y;
 59         no[k].ma=y;
 60         return ;
 61     }
 62     int mid = (no[k].li+no[k].ri)/2;
 63     if(x<=mid)
 64     {
 65         singlemodify(k*2,x,y);
 66     }
 67     else
 68     {
 69         singlemodify(k*2+1,x,y);
 70     }
 71     //维护线段树
 72     no[k].mi=min(no[k*2].mi,no[k*2+1].mi);
 73     no[k].ma=max(no[k*2].ma,no[k*2+1].ma);
 74 }
 75 //恢复指定坐标的值,
 76 void recovery(int k,int x)
 77 {
 78     if(no[k].li==no[k].ri)
 79     {
 80         no[k].mi=m+1;
 81         no[k].ma=0;
 82         return ;
 83     }
 84     int mid = (no[k].li+no[k].ri)/2;
 85     if(x<=mid)
 86     {
 87         recovery(k*2,x);
 88     }
 89     else
 90     {
 91         recovery(k*2+1,x);
 92     }
 93     //维护线段树
 94     no[k].mi=min(no[k*2].mi,no[k*2+1].mi);
 95     no[k].ma=max(no[k*2].ma,no[k*2+1].ma);
 96 }
 97 
 98 //区间最值,flag为1时表示最小,为0时表示最大
 99 int querymaxin(int k,int l,int r,int flag)
100 {
101     //到对应层时返回值
102     if(no[k].li==l&&no[k].ri==r)
103     {
104         if(flag==1)
105         {
106             return no[k].mi;
107         }
108         else
109         {
110             return no[k].ma;
111         }
112     }
113     //取中值
114     int mid=(no[k].li+no[k].ri)/2;
115     if(r<=mid)
116     {
117         return querymaxin(k*2,l,r,flag);
118     }
119     else if(l>mid)
120     {
121         return querymaxin(k*2+1,l,r,flag);
122     }
123     else
124     {
125         if(flag==1)
126         {
127             return min(querymaxin(k*2,l,mid,flag),querymaxin(k*2+1,mid+1,r,flag));
128         }
129         else
130         {
131             return max(querymaxin(k*2,l,mid,flag),querymaxin(k*2+1,mid+1,r,flag));
132         }
133 
134     }
135 }
136 
137 int main()
138 {
139     while(scanf("%d %d",&m,&n)!=EOF)
140     {
141         build(1,1,m);
142         //记录毁掉的村庄的编号
143         int history[50000];
144         int ans=0;
145         while(n--)
146         {
147             char ch[2];
148             int s;
149             cin>>ch;
150             if(ch[0]=='D')
151             {
152                 scanf("%d",&history[ans]);
153                 singlemodify(1,history[ans],history[ans]);
154                 ans++;
155             }
156             else if(ch[0]=='Q')
157             {
158                 cin>>s;
159                 int mi = querymaxin(1,s,m,1);
160                 int ma = querymaxin(1,1,s,0);
161                 if(mi==ma)
162                 {
163                     printf("0\n");
164                 }
165                 else
166                 {
167                     //记得要减一
168                     printf("%d\n",mi-ma-1);
169                 }
170             }
171             else if(ch[0]=='R')
172             {
173                 ans--;
174                 recovery(1,history[ans]);
175             }
176         }
177     }
178 }

猜你喜欢

转载自www.cnblogs.com/mzchuan/p/11823235.html
今日推荐