hdu1540 Tunnel Warfare【线段树】

时间:2022-01-05 10:25:59

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!

Input

The 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.

Output

Output 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

区间合并

用Ltree 和Rtree分别存【L,R】区间中从L开始到右侧最长的连续区间长度 和从R开始到左侧最长的连续区间长度

pushup的时候需要比较左孩子的Ltree能不能和右孩子的相连 右孩子的Rtree能不能和左孩子的相连

destroy 和rebuilt 都是对点进行更新

query的时候,我们和单点查询一样,直到找到当前点的叶子节点一路查询即可。

这里重点在于区间合并的操作,首先我们讨论当前区间点的问题:

如果当前区间点从左到右能够覆盖查询点,那么ans=max(ans,Lsum【now】);

同理,如果当前区间从右到左能够覆盖查询点,那么ans=max(ans,Rsum【now】);

然后我们讨论当前区间和兄弟节点的合并查询问题:

如果当前区间点是左儿子,那么对应我们查询左儿子的Rsum和右儿子的Lsum是否能够连接并且覆盖查询点,如果可以,那么对应ans=max(ans,Rsum【now】+Lsum【now+1】)

如果当前区间点是右儿子,那么对应我们查询右儿子的Lsum和左儿子的Rsum是否能够连接并且覆盖查询点,如果可以,那么对应ans=max(ans,Lsum【now】+Rsum【now-1】);


#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stack>
#define inf 1e18
using namespace std; int m, n;
const int maxn = 50005;
int Ltree[maxn << 2], Rtree[maxn<<2]; void pushup(int l, int r, int rt)//更新
{
Ltree[rt] = Ltree[rt * 2];
Rtree[rt] = Rtree[rt * 2 + 1];
int m = (l + r) / 2;
if(Ltree[rt * 2] == (m - l + 1))Ltree[rt] += Ltree[rt * 2 + 1];
if(Rtree[rt * 2 + 1] == (r - m))Rtree[rt] += Rtree[rt * 2]; } void build(int l, int r, int rt)
{
if(l == r){
Ltree[rt] = Rtree[rt] = l - r + 1;
return;
}
int m = (l + r) >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
pushup(l, r, rt);
} void update(int L, int C, int l, int r, int rt)
{
if(l == r){
if(C == -1){
Ltree[rt] = Rtree[rt] = 0;
}
else{
Ltree[rt] = Rtree[rt] = 1;
}
return;
}
int m = (l + r) >>1;
if(L <= m) update(L, C, l, m, rt << 1);
else update(L, C, m + 1, r, rt << 1 | 1);
pushup(l, r, rt);
} /*void update(int L, int R, int l, int r, int rt)
{
if(tree[rt] == r - l + 1){//本区间完全在操作区间内
return;
}
if(l == r){
tree[rt] = sqrt(tree[rt]);
return;
}
int m = (l + r) >> 1;
if(L <= m) update(L, R, l, m, rt << 1);
if(R > m) update(L, R, m + 1, r, rt << 1 | 1);
pushup(rt);
}
*/
int query(int L, int l, int r, int rt)
{
if(l == r){
return max(Ltree[rt], Rtree[rt]);
}
pushup(l, r, rt);
int m = (l + r) >> 1;
//pushdown(rt, m - l + 1, r - m); int ans = 0;
if(L >= l && L <= r){
if(Ltree[rt] >= L - l + 1)
ans = max(ans, Ltree[rt]);
if(Rtree[rt] >= r - L + 1)
ans = max(ans, Rtree[rt]);
}
if(rt % 2 == 0){
if(Rtree[rt] >= r - L + 1)
ans = max(ans, Rtree[rt] + Ltree[rt + 1]);
}
else{
if(Ltree[rt] >= L - l + 1)
ans = max(ans, Ltree[rt] + Rtree[rt - 1]);
}
if(L <= m)
ans = max(ans, query(L, l, m, rt << 1));
if(L > m)
ans = max(ans, query(L, m + 1, r, rt << 1|1));
pushup(l, r, rt);
return ans;
} int main()
{
while(scanf("%d%d", &n, &m) != EOF){
stack<int>des;
build(1, n, 1);
for(int i = 0; i < m; i++){
getchar();
char ch;
int a;
scanf("%c", &ch);
if(ch == 'R'){
if(des.size() == 0)continue;
a = des.top();des.pop();
update(a, 1, 1, n, 1);
}
else{
scanf("%d", &a);
if(ch == 'D'){
des.push(a);
update(a, -1, 1, n, 1);
}
else{
printf("%d\n", query(a, 1, n, 1));
}
}
}
}
return 0;
}