http://poj.org/problem?id=2892
题意:
给出直线上一系列的村庄,如果相邻村庄都没有被破坏,
则两村庄是连接的,题目给出一系列的破坏操作,对指定号码的村庄进行破坏,
还有一系列的询问操作,询问与指定号码的村庄直接相连或间接相连的村庄有几个,
还有一个修复操作,是对最后破坏的村庄进行修复。
POJ能A 在hdu1540 WA QAQ
#include "stdio.h"
#include "string.h"
#include "math.h"
const int maxn = 50005;
int n,q,ad;
int c[maxn],stack[maxn]; //stack记录摧毁的点
bool vis[maxn];
int lowbit( int x )
{
return x&(-x);
}
void updata( int x )
{
while( x <= n )
{
c[x] += ad;
x += lowbit(x);
}
}
int getsum(int x)
{
int ans = 0;
while( x >= 1 )
{
ans += c[x];
x -= lowbit(x);
}
return ans;
}
int find_k_th( int k ) // 二分找sum为k的最小位置
{
int ans = 0,cur=0;
int i = 1<<20;
while( i >= 1 )
{
ans += i;
if( ans >= n || cur + c[ans] >= k )
ans -= i;
else
cur += c[ans];
i >>= 1;
}
return ans + 1;
}
int main()
{
//freopen("data.txt","r",stdin);
int i;
char ch[3];
int sum,ld,rd;
while( scanf("%d%d",&n,&q)==2 )
{
int top = 0,u;
memset( vis,0,sizeof(vis) );
memset( c,0,sizeof(c) );
getchar();
for( i = 1; i <= q; i ++ )
{
scanf("%s",ch);
if( ch[0] == 'D' )
{
scanf("%d",&u);
stack[++top] = u;
ad = 1;
if( vis[u] == 0 )
updata( u );
vis[u] = 1;
}
else if( ch[0] == 'Q' )
{
scanf("%d",&u);
if( vis[u] ) puts("0");
else
{
sum = getsum( u ); //u前有sum个点被摧毁
if( !sum )
ld = 0;
else
ld = find_k_th( sum );
if( sum == top )
rd = n + 1;
else
rd = find_k_th( sum+1 );
printf("%d\n",rd - ld - 1);
}
}
else
{
if( top ) //栈非空
{
u = stack[top--];
ad = -1;
if( vis[u] )
updata( u );
vis[u] = 0;
}
}
}
}
return 0;
}