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

Tunnel Warfare

题意:有 n n 个村庄,如果对于村庄 i i j j 都存在,那么我们就称其关系为连续,然后会有三个操作:

  1. D      X D\;\;X 摧毁第 X X 个村庄。
  2. Q      X Q\;\;X 询问包含村庄 X X 的最大连续村庄的长度。
  3. R      X R\;\;X 复原上一次摧毁的村庄。

题解:因为涉及到了单点区间询问以及单点区间更新,我们需要用线段树来维护一些信息了。
首先要有的肯定是每个区间的最大连续长度,但是只有这一个信息明显是无法合并区间的,因此我们可以再增加两个信息:从区间左端点开始往右最大的连续长度,从区间右端点开始往左的最大的连续长度。这样我们就可以方便我们合并了。

现在我们来考虑如何合并两个区间信息。

为了描述方便,在这里称父节点为 r t rt ,左孩子 l s o n lson ,右孩子为 r s o n rson ,最大连续长度为 l e n len ,从左端点开始的最大连续长度为 l _ l e n l\_len ,从右端点开始的最大连续长度为 r _ l e n r\_len

如果左孩子全部连续,那么 r t rt l _ l e n l\_len 为左孩子的 l e n len 加右孩子的 l _ l e n l\_len

如果右孩子全部连续,那么 r t rt r _ l e n r\_len 为右孩子的 l e n len 加左孩子的 r _ l e n r\_len

r t rt l e n len m a x { l s o n r _ l e n + r s o n l _ l e n ,      l s o n l e n ,      r s o n l e n } max\{lson_{r\_len} + rson_{l\_len},\;\;lson_{len},\;\;rson_{len}\}

但是要注意如何查询。如果 x x 在左孩子里,那么需要看 x x 是否在左孩子的 r _ l e n r\_len 的范围里,如果在的话,那么最大连续长度就肯定为 r _ l e n r\_len 与右孩子的 l _ l e n l\_len 的和,否则就再去左孩子里去找即可; x x 在右孩子里的时候,情况同左孩子一样处理。

代码

#include<bits/stdc++.h>

#define DEBUG(x) std::cerr << #x << '=' << x << std::endl

using namespace std;
const int N = 5E4+10;
struct node{
	int lt_len,rt_len,len;
}tr[N << 2];

#define len(x) tr[x].len
#define r_len(x) tr[x].rt_len
#define l_len(x) tr[x].lt_len

void pushup(int rt,int l,int r,int mid)
{
	len(rt) = max(len(rt << 1), len(rt << 1 | 1));
	len(rt) = max(len(rt), l_len(rt << 1 | 1) + r_len(rt << 1));
	l_len(rt) = l_len(rt << 1); r_len(rt) = r_len(rt << 1 | 1); 
	if(l_len(rt) == mid - l + 1) l_len(rt) += l_len(rt << 1 | 1);
	if(r_len(rt) == r - mid) r_len(rt) += r_len(rt << 1);
}

void build(int rt,int l,int r)
{
	if(l == r) {
		tr[rt].rt_len = tr[rt].lt_len = tr[rt].lt_len = 1;
		return;
	}
	int mid = l + r >> 1;
	build(rt << 1, l, mid);
	build(rt << 1 | 1, mid + 1, r);
	pushup(rt, l, r, mid);
}

void update(int rt,int l,int r,int x,int d)
{
	if(l == x && r == x) {
		len(rt) = l_len(rt) = r_len(rt) = d;
		return;	
	}
	int mid = l + r >> 1;
	if(x <= mid) update(rt << 1, l, mid, x, d);
	else update(rt << 1 | 1, mid + 1, r, x, d);
	pushup(rt, l, r, mid);
}

int query(int rt,int l,int r,int x)
{
	if(len(rt) == 0 || len(rt) == r - l + 1) {
		return len(rt);
	}
	int mid = l + r >> 1;
	if(x <= mid) {
		if(mid - r_len(rt << 1) < x) {
			return r_len(rt << 1) + l_len(rt << 1 | 1);
		}
		return query(rt << 1, l, mid, x);
	}else {
		if(mid + l_len(rt << 1 | 1) >= x) {
			return l_len(rt << 1 | 1) + r_len(rt << 1);
		}
		return query(rt << 1 | 1, mid + 1, r, x);
	}
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
    ios::sync_with_stdio(false); cin.tie(0);
	int n,m,x;
	while(cin >> n >> m) {
		build(1, 1, n);
		stack<int> st;
		char c;
		for(int i = 0; i < m; ++i) {
			cin >> c;
			if(c == 'D') {
				cin >> x;
				st.push(x);
				update(1, 1, n, x, 0);
			}else if(c == 'Q') {
				cin >> x;
				cout << query(1, 1, n, x) << endl;
			}else{
				if(!st.empty()) {
					update(1, 1, n, st.top(), 1);
					st.pop();
				}
			}
		}
	}
    return 0;
}

发布了219 篇原创文章 · 获赞 23 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Eternally831143/article/details/88368746