POJ2892 HDU 1540 Tunnel Warfare, 树状数组

60 篇文章 0 订阅
11 篇文章 0 订阅

利用树状数组的find_k_th实现找到sum为k的最小位置,  时间复杂度为O(log(n))

/*******************************************************************************
 # Author : Neo Fung
 # Email : neosfung@gmail.com
 # Last modified: 2012-01-29 22:22
 # Filename: POJ2892 HDU 1540 Tunnel Warfare.cpp
 # Description : 利用树状数组的find_k_th实现找到sum为k的最小位置, 
 时间复杂度为O(log(n))
 ******************************************************************************/
#ifdef _MSC_VER
#define DEBUG
#endif

#include <fstream>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <string>
#include <limits.h>
#include <algorithm>
#include <stack>
#include <math.h>
#define MAX 50010
#define lowbit(x) (x&(-x))
using namespace std;

int c[MAX];
stack<int> order;

int getsum(int x)
{
	int sum=0;
	for(int i=x;i>0;i-=lowbit(i))
			sum+=c[i];
	return sum;
}

void updata(const int &x,const int &n, const int &val)
{
	for(int i=x;i<=n;i+=lowbit(i))
		c[i]+=val;
}

//找第k小的位置
int find_k_th(int k,const int &n, const int &logn) 
{
  int cnt=0,cur=0;
  for (int i=logn;i>=0;--i) {
    cur+=(1<<i); 
    if (cur>n || cnt+c[cur]>=k) cur-=(1<<i); 
    else cnt+=c[cur];
  }
  return cur+1;
}


int main(void)
{
#ifdef DEBUG  
  freopen("../stdin.txt","r",stdin);
  freopen("../stdout.txt","w",stdout); 
#endif  

  int n,m,x;
  char ch;

  while(~scanf("%d%d",&n,&m))
  {
	  memset(c,0,sizeof(c));
	  while(!order.empty())
		  order.pop();
    n+=2;
    updata(1,n,1);  //1号位和n+2号位用作哨兵, 只用[2,n+1]记录有效数据;
    updata(n,n,1);
    int logn = int(log(n+1.0)/log(2.0));
	  while(m--)
	  {
      getchar();
		  scanf("%c",&ch);
		  if(ch=='D')
      {
        scanf("%d",&x);
        ++x;
			  order.push(x);
			  updata(x,n,1);
		  }
		  else if(ch=='R')
		  {
			  x=order.top();
			  order.pop();
			  updata(x,n,-1);
		  }
		  else
		  {
        scanf("%d",&x); ++x;
        int sum=getsum(x),pre=find_k_th(sum,n,logn),next=find_k_th(sum+1,n,logn);
        if (pre!=x) printf("%d\n",next-pre-1);
        else printf("0\n");
      }
	  }
  }

	return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值