HDOJ-1540 Tunnel Warfare(线段树+二分)

当a村庄存在时,用二分找到1到a-1内核a村庄相连的最大村庄数目,再找到a+1,到n内和a村庄相连的最大村庄数目

#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>
#include <cmath>
#include <stack>
#define maxn 50005
using namespace std;
typedef long long ll;

int num[maxn<<2], vis[maxn];
stack<int> sta;
void Update(int n, int l, int r, int s, int d){

    if(l == r){
        num[n] = d;
        return ;
    }
    int mid = (l + r) >> 1;
    if(s <= mid)
     Update(n<<1, l, mid, s, d);
    else
     Update(n<<1|1, mid+1, r, s, d);
    num[n] = num[n<<1] && num[n<<1|1];
}
void Query(int n, int l, int r, int L, int R, int &s){

    if(l == L && R == r){
        s = s && num[n];
        return ;
    }
    int mid = (l + r) >> 1;
    if(R <= mid)
     Query(n<<1, l, mid, L, R, s);
    else if(L > mid)
     Query(n<<1|1, mid+1, r, L, R, s);
    else{
        Query(n<<1, l, mid, L, mid, s);
        Query(n<<1|1, mid+1, r, mid+1, R, s);
    }
}
int main(){

//  freopen("in.txt", "r", stdin);
    int n, m;

    while(scanf("%d%d ", &n, &m) == 2){

        while(!sta.empty())
         sta.pop();
        memset(vis, 0, sizeof(vis));
        for(int i = 1; i <= (n<<2); i++)
          num[i] = 1;
        char ch;
        int a;
        while(m--){

            scanf("%c ", &ch);
            if(ch == 'D'){
                scanf("%d ", &a);
                vis[a] = 1;
                Update(1, 1, n, a, 0);
                sta.push(a);
            }
            else if(ch == 'R'){
                int b = sta.top();
                sta.pop();
                vis[b] = 0;
                Update(1, 1, n, b, 1);
            }
            else if(ch == 'Q'){
                scanf("%d ", &a);
                if(vis[a]){
                    printf("%d\n", 0);
                    continue;
                }
                int cnt = 1;
                int l = 1, r = a;
                if(r != 1){
                while(l < r){

                    int s = 1;
                    int mid = (l + r) >> 1;
                    Query(1, 1, n, mid, a-1, s);
                    if(s)
                      r = mid;
                    else
                     l = mid+1;
                }
                cnt += a - l;
              }
              if(l != n){
                l = a + 1;
                r = n + 1;
                while(l < r){
                    int s = 1;
                    int mid = (l + r) >> 1;
                    Query(1, 1, n, a+1, mid, s);
                    if(s)
                     l = mid + 1;
                    else
                     r = mid;
                } 
                cnt += l - a - 1;
              }
              printf("%d\n", cnt);
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值