hdu 1540 (poj 2892) Tunnel Warfare

题目:
hdu
poj

题意:
N个村子连成一条线,相邻的村子相连(没有被摧毁)。三个命令:
D x,表示x村庄被摧毁;
Q x,表示与x直接或间接相连的村庄有多少个,当然包括他自己(被摧毁为0);
R,表示恢复最后被摧毁的村庄。

思路:

  1. 记录每个线段的从左边起的最大连续区间和从右边起的最大连续区间

  2. 如果在左边的最大连续区间 or 右边的最大连续区间,则return左边的最大连续区间 or 右边的最大连续区间(线段树的结点是1)
    线段树的结点是1的情况

  3. 如果在左边的最大连续区间 or 右边的最大连续区间,则return左边的最大连续区间 + (结点-1)的右边的最大连续区间 or 右边的最大连续区间 + (结点+1)的左边的最大连续区间(线段树的结点不是1)
    在左边的最大连续区间在右边的最大连续区间

  4. 如果不在左边的最大连续区间 or 右边的最大连续区间,则递归找左子树 or 右子树

在中间的情况

代码:

#include <iostream>
#define lson l, mid, pos << 1
#define rson mid + 1, r, pos << 1 | 1
using namespace std;
const int MAXN = 5e4 + 10;
struct node{
	int sum;  //该线段的长度(~len)
	int l, r;  //左边的最大连续区间, 右边的最大连续区间
}tree[MAXN<<2];
int a[MAXN], ai;  //栈
void updata(int p){
	tree[p].l = (tree[p<<1].l == tree[p<<1].sum) ? tree[p<<1].l + tree[p<<1|1].l : tree[p<<1].l;
	tree[p].r = (tree[p<<1|1].r == tree[p<<1|1].sum) ? tree[p<<1|1].r + tree[p<<1].r : tree[p<<1|1].r;
}
void build(int l, int r, int pos){
	if (l == r){
		tree[pos].sum = tree[pos].l = tree[pos].r = 1;
		return;
	}
	int mid = (l + r) >> 1;
	build(lson);
	build(rson);
	updata(pos);
	tree[pos].sum = tree[pos<<1].sum + tree[pos<<1|1].sum;  //只更新1次
} 
void add(int i, int v, int l, int r, int pos){
	if (l == r){
		tree[pos].l = tree[pos].r = v;
		return;
	}
	int mid = (l + r) >> 1;
	if (mid >= i)
		add(i, v, lson);
	else
		add(i, v, rson);
	updata(pos);
}
int find(int i, int l, int r, int pos){
	if (l == r)
		return 0;
	if (pos == 1){
		if (i - l + 1 <= tree[pos].l)
			return tree[pos].l;
		if (r - i + 1 <= tree[pos].r)
			return tree[pos].r;
	}
	if (tree[pos].l && i - l + 1 <= tree[pos].l)
		return tree[pos].l + tree[pos-1].r;  //     r<-pos-1 [ pos ]->l
	if (tree[pos].r && r - i + 1 <= tree[pos].r)
		return tree[pos].r + tree[pos+1].l;  //     r<-[ pos ] pos+1->l
	int mid = (l + r) >> 1;
	if (mid >= i)
		return find(i, lson);
	else
		return find(i, rson);
}
int main(){
//	freopen("_in.txt", "r", stdin);
//	freopen("_out1.txt", "w", stdout);
	int n, m, ans, b;
	char op;
	while (~scanf("%d%d", &n, &m)){  //一定要加while,不然会wa
		ai = 0;
		build(1, n, 1);
		while (m--){
			scanf(" %c", &op);
			if (op == 'D'){
				scanf("%d", &a[++ai]);
				add(a[ai], 0, 1, n, 1);
			} 
			else if (op == 'Q'){
				scanf("%d", &b);
				ans = find(b, 1, n, 1);
				printf("%d\n", ans); 
			}
			else
				add(a[ai--], 1, 1, n, 1);
		}
	}
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值