POJ 2892 Tunnel Warfare (树状数组+二分)

题目大意:

三个操作

D pos  将pos位置摧毁,让它和周围不相连。

Q pos 问和pos 相连的有多少个村庄。

R 修复最近摧毁的村庄。

思路分析:

树状数组记录这个区间有多少个1。

如果  [s-e] 有e-s+1个1 的话。那么这个区间是相连的。

这样的话,我们就可以用二分的办法求出与某个位置最大相连的数量。

还有这里二分

while(l<=r)

{

if(满足)

{

ans=mid;

l=mid+1;

}

else r=mid-1;

}

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define maxn 55555
using namespace std;
int n,m;
int c[maxn];
int lowbit(int x)
{
    return (x&(-x));
}
int sum(int x)
{
    int ret=0;
    while(x>0)
    {
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}
void add(int x,int d)
{
    while(x<=n)
    {
        c[x]+=d;
        x+=lowbit(x);
    }
}
int top;
int stack[maxn];
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(c,0,sizeof c);
        for(int i=1;i<=n;i++)
        {
            add(i,1);
        }
        char str[5];

        while(m--)
        {
            scanf("%s",str);
            if(str[0]=='D')
            {
                int pos;
                scanf("%d",&pos);
               // if(sum(pos)-sum(pos-1)==0)continue;
                add(pos,-1);
                stack[top++]=pos;
            }
            else if(str[0]=='R')
            {
                int pos=stack[--top];
                add(pos,1);
            }
            else
            {
                int cur,l,r,ans,rs,re;
                scanf("%d",&cur);
                if(sum(cur)-sum(cur-1)==0)
                {
                    printf("0\n");
                    continue;
                }
                l=cur;r=n;
                while(l<=r)
                {
                    int mid=(l+r)>>1;
                    if(sum(mid)-sum(cur-1)==mid-cur+1)
                    {
                        ans=mid;
                        l=mid+1;
                    }
                    else r=mid-1;
                }
                re=ans;

                l=1;r=cur;
                while(l<=r)
                {
                    int mid=(l+r)>>1;
                    if(sum(cur)-sum(mid-1)==cur-mid+1)
                    {
                        ans=mid;
                        r=mid-1;
                    }
                    else l=mid+1;
                }
                rs=ans;
               // printf("%d %d\n",re,rs);
                printf("%d\n",re-rs+1);
            }
        }
    }
    return 0;
}

POJ 2892 Tunnel Warfare (树状数组+二分)

时间: 2024-12-21 14:43:28

POJ 2892 Tunnel Warfare (树状数组+二分)的相关文章

POJ 2892 Tunnel Warfare [树状数组]

题目链接: http://poj.org/problem?id=2892 题意:一个长度为n的线段,下面m个操作 D x 表示将单元x毁掉 R  表示修复最后毁坏的那个单元 Q x  询问这个单元以及它周围有多少个连续的单元,如果它本身已经被毁坏了就是0 思路: 这道题是经典的线段树入门题目,由于只是进行单点更新, 不涉及区间更新,用树状数组更简洁. 维护两个树状数组,一个是把所有的1进行维护,一个是把所有的0进行维护. 翻转(炸毁或修复)任何一个单元,同时修改这两个树状数组,仅仅是为了 合并 

POJ 2182 Lost Cows (树状数组 &amp;&amp; 二分查找)

题意:给出数n, 代表有多少头牛, 这些牛的编号为1~n, 再给出含有n-1个数的序列, 每个序列的数 ai 代表前面还有多少头比 ai 编号要小的牛, 叫你根据上述信息还原出原始的牛的编号序列 分析:如果倒着看这个序列的话, 那序列的最后一个元素就能够确定一个编号.举个例子:如果序列的最后一个元素为0, 那就说明这头牛前面再也没有比它编号更小的牛了, 所以这头牛的编号肯定是最大的, 我们只要给它所在的编号加个标记, 然后继续根据倒数第二个.第三个--来依次确定便可还原整个序列, 这里可以使用树

HDU 1540 &amp;&amp; POJ 2892 Tunnel Warfare (线段树,区间合并).

~~~~ 第一次遇到线段树合并的题,又被律爷教做人.TAT. ~~~~ 线段树的题意都很好理解吧.. 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1540 http://poj.org/problem?id=2892 ~~~~ 我的代码:200ms #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #defin

POJ 2828 Buy Tickets (线段树 or 树状数组+二分)

题目链接:http://poj.org/problem?id=2828 题意就是给你n个人,然后每个人按顺序插队,问你最终的顺序是怎么样的. 反过来做就很容易了,从最后一个人开始推,最后一个人位置很容易就确定了,那最后第二个人的位置也可以推(与最后一个人的位置无关)...依次就都可以确定所有的人了. 用前缀和的思想,要是这个人的位置确定了,那么就标记这个人位置的值为0,然后回溯更新,跟求逆序对个数的思想比较类似. 线段树: 1 #include <iostream> 2 #include &l

HDU 2852 KiKi&#39;s K-Number (树状数组 &amp;&amp; 二分)

题意:给出对容器的总操作次数n, 接下来是这n个操作.这里对于一个容器提供三种操作, 分别是插入.删除和查找.输入0  e表示插入e.输入1  e表示删除e,若元素不存在输出No Elment!.输入2  e  k表示查找比e大且第k大的数, 若不存在则输出Not Find! 分析:这里考虑树状数组做的原因是在第三个操作的时候, 只要我们记录了元素的总数, 那通过求和操作, 便能够高效地知道到底有多少个数比现在求和的这个数要大, 例如 tot - sum(3)就能知道整个集合里面比3大的数到底有

hdu 1541/poj 2352:Stars(树状数组,经典题)

Stars Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4052    Accepted Submission(s): 1592 Problem Description Astronomers often examine star maps where stars are represented by points on a plan

ZOJ 3635 树状数组+二分

这题那时怎么想就是想不出来--而且今晚没有多大状态,自己都晕了--一题没做出来-- baoge解释好久才懂--唉--线段树,树状数组用得还是不够熟啊-- WA了二发,才知道二分错了,二分好久不用,老是出错了现在-- #include<iostream> #include<cstring> #include<string> #include<cstdio> #define sca(a) scanf("%d",&a) #define

HDU 5592 ZYB&#39;s Premutation(树状数组+二分)

题意:给一个排列的每个前缀区间的逆序对数,让还原 原序列. 思路:考虑逆序对的意思,对于k = f[i] - f[i -1],就表示在第i个位置前面有k个比当前位置大的数,那么也就是:除了i后面的数字之外,它是在剩下的数字当中第k+1大的. 知道这个之后,可以用树状数组来帮助找出剩下的数中第k大的数,刚开始我们可以让1-n中每个元素都标记为1,那么他们的前缀和就代表它是第几小.所以,我们可以对于他们的和来二分快速寻找第k大数.其实在树状数组里面是按照第(i-k)小来找的.找完之后要删除这个元素的

poj 2155 二维树状数组

http://poj.org/problem?id=2155 Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 17721   Accepted: 6653 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. I