Tunnel Warfare HDU - 1540

3 篇文章 0 订阅
1 篇文章 0 订阅

题意:
1. 从N个村庄(标号1到N)村庄彼此相连,如果未被摧毁
2. 三种操作
- 摧毁第x个vilage
- 询问包含x在内最长连续的未摧毁城市个数
- 恢复最后一个城市

节点的定义:
1. start(起点),end(结束点)
2. Mlen(最长长度),Len(以start为起点的最长连续村庄长度),Rlen(以end为结束最右连续村庄的长度)

思路:
1. 本题运用了分治算法和线段树
- 分治处理在于处理跨左右子树的可能
2. 注意点
- 注意maxlen不仅可以等于左右子线段的最长的长度,也可以等于左子线段的Rlen加上右子线段的Llen
- 注意左子线段右子线段中的村庄均未被摧毁时,显然有 left.max + right.len >= left.llen故可直接更新,同理右子线段也可以如此处理
3. 询问包含x在内最长连续的未摧毁城市个数
- 当target > midtarget <= nodes[index << 1 | 1].start + nodes[index << 1 | 1].Llen - 1 时应为target在右子线段的左端连续线段上故应计入左子树的右端连续线段的长度,同理处理target <= mid时的情况

#include <bits/stdc++.h>
using namespace std;
struct Node
{
  int start, end;
  int Mlen, Llen, Rlen;
};
const int MAX_N = 50000 ;
Node nodes[MAX_N * 4 + 10];
stack<int> stk;
void destroy ( int index, int target, bool flag )
{
  if ( nodes[index].start == nodes[index].end )
  {
    if ( flag )
    { nodes[index].Llen = nodes[index].Rlen = nodes[index].Mlen = 0; }
    else
    { nodes[index].Llen = nodes[index].Rlen = nodes[index].Mlen = 1; }
    return;
  }
  int mid = ( nodes[index].start + nodes[index].end ) >> 1;
  if ( target <= mid )
  {
    destroy ( index << 1, target, flag );
  }
  else
  {
    destroy ( index << 1 | 1, target, flag );
  }
  nodes[index].Llen = nodes[index << 1].Llen;
  nodes[index].Rlen = nodes[index << 1 | 1].Rlen;
  nodes[index].Mlen = max ( max ( nodes[index << 1].Mlen, nodes[index << 1 | 1].Mlen ),
                            nodes[index << 1].Rlen + nodes[index << 1 | 1].Llen );
  if ( nodes[index << 1].Mlen == nodes[index << 1].end - nodes[index << 1].start + 1 )
  {
    nodes[index].Llen = nodes[index << 1].Mlen + nodes[index << 1 | 1].Llen;
  }
  if ( nodes[index << 1 | 1].Mlen == nodes[index << 1 | 1].end - nodes[index << 1 | 1].start + 1 )
  {
    nodes[index].Rlen = nodes[index << 1 | 1].Mlen + nodes[index << 1].Rlen;
  }
  return;
}

void build ( int index, int start, int end )
{
  nodes[index].start = start;
  nodes[index].end = end;
  nodes[index].Llen = nodes[index].Mlen = nodes[index].Rlen = end - start + 1;
  if ( start == end )
  {
    return;
  }
  int mid = ( start + end ) >> 1;
  build ( ( index << 1 ), start, mid );
  build ( ( index << 1 ) + 1, mid + 1, end );
}
int cnt ( int index, int target )
{
  if ( nodes[index].start == nodes[index].end || nodes[index].Mlen == 0 )
  {
    return nodes[index].Mlen;
  }
  if ( nodes[index].Mlen == nodes[index].end - nodes[index].start + 1 )
  {
    return nodes[index].Mlen;
  }
  int mid = ( nodes[index].start + nodes[index].end ) >> 1;
  if ( target > mid )
  {
    if ( target <= nodes[index << 1 | 1].start + nodes[index << 1 | 1].Llen - 1 )
    {
      return cnt ( index << 1 | 1, target ) + cnt ( index << 1, mid );
    }
    else
    {
      return cnt ( index << 1 | 1, target );
    }
  }
  else
  {
    if ( target >= nodes[index << 1].end - nodes[index << 1].Rlen + 1 )
    {
      return cnt ( index << 1, target ) + cnt ( index << 1 | 1, mid + 1 );
    }
    else
    {
      return cnt ( index << 1, target );
    }
  }
}
int main()
{
  ios::sync_with_stdio ( false );
  int N, M;
  while ( cin >> N >> M )
  {
    build ( 1, 1, N );
    while ( M-- )
    {
      char op;
      int u;
      cin >> op;
      if ( op == 'Q' )
      {
        cin >> u;
        cout << cnt ( 1, u ) << endl;
      }
      else if ( op == 'D' )
      {
        cin >> u;
        destroy ( 1, u, true );
        stk.push ( u );
      }
      else if ( op == 'R' )
      {
        u = stk.top();
        stk.pop();
        destroy ( 1, u, false );
      }
    }
  }

  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值