poj2892 树状数组+二分

题意:求0所在位置两点连续0的个数,不断更新某个点,将这个点变成0或1

用数状数组维护这个表,变成0,1就更新某个点,这是树状数组的特长。查询的时候,对两边二分就行了


//
//  main.cpp
//  poj2892
//
//  Created by He Xilin on 12-4-30.
//  Copyright 2012年 UESTC,ZSC. All rights reserved.
//
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 50000;
int c[MAXN + 10];
void  Delete(int x)//树状数组更新点
{
	while(x<=MAXN)
	{
		c[x]++;
		x += x & ( x ^ (x - 1));
	}
}
void  recover(int x)//树状数组更新点
{
	while(x<=MAXN)
	{
		c[x]--;
		x += x & (x ^ (x - 1));
	}
}
int sum(int x)//树状数组求和
{
	int ans = 0;
	while(x > 0)
	{
		ans += c[x];
		x -= x & (x ^ (x - 1));
	}
	return ans;
}
int binary(int x, int s, int t,bool isSecond)//二分左边的区间
{
	if(sum(t) == 0)
	{
		return 0;
	}
	int ans = -1;
	int total = sum(x);
	int mid;
	while(s <= t)
	{
		mid = ((s + t) >> 1);
		int flag = sum(mid);
		if(total - flag == 0)
		{
			ans = mid;
			t = mid - 1;
		}
		else 
		{
			if(isSecond == false)
			  s = mid + 1;
			else
			  t = mid - 1;
		}
	}
	return ans == -1 ? mid : ans;
}
int binary2(int x, int s, int t,bool isSecond)//二分右边的区间
{
	int total = sum(x);
	int ans  = -1;
	if(sum(t) - total == 0)
	{
		return t + 1;
	}
	int mid;
	while(s <= t)
	{
		mid = ((s + t) >> 1);
		int flag = sum(mid);
		if(flag - total == 1)
		{
			//return mid;
			ans = mid;
			t = mid - 1;
		}
		else  if(flag - total < 1)
		{
			  s = mid + 1;
		}
		else
		{
			t = mid - 1;
		}
	}
	return ans == -1 ? mid: ans;
}

int query(int n,int x)//查询
{
	if(sum(x) - sum(x - 1) != 0)
	{
		return 0;
	}
	int s = 1;
	int t = x - 1;
	int mid1 = binary(x,s, t,false);
	s = x + 1;
	t = n;
	int mid2 = binary2(x, s, t,true);
	//printf("%d, %d\n",mid1,mid2);
	return mid2 - mid1  - 1;
}
int main (int argc, const char * argv[])
{
	//freopen("poj2892.in", "r", stdin);
	int n,m;
	while(scanf("%d %d",&n,&m) != EOF)
	{
		int sta[MAXN + 10];
		int cnt = -1;
		memset(c,0,sizeof(c));
		int i;
		char ch[2];
		int num;
		for(i = 0; i < m; i++)
		{
			scanf("%s",ch);
			if(strcmp(ch,"D") == 0)
			{
				scanf("%d",&num);
				sta[++cnt] = num;
				Delete(num);
			}
			else if(strcmp(ch,"R") == 0)
			{
				//scanf("%d",&num);
				recover(sta[cnt--]);
			}
			else
			{
				scanf("%d",&num);
				if(num == 6)
				{
					int debug = 1;
				}
				int ans = query(n,num);
				printf("%d\n",ans);
			}
		}
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值