每个线段维护左起连续长度,和右起连续长度,然后每次查询时讨论x所在连续段是否同时存在两个子段中,分类讨论即可
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <stack>
#define MAX 50007
using namespace std;
int n,m,a;
char s[5];
stack<int> stk;
struct Tree
{
int l , r , llen , rlen;
}tree[MAX<<2];
void build ( int u , int l , int r )
{
tree[u].l = l , tree[u].r = r;
tree[u].llen = tree[u].rlen = r-l+1;
if ( l == r ) return;
int mid = l + r >> 1;
build ( u<<1 , l , mid );
build ( u<<1|1 , mid+1 , r );
}
void push_up ( int u )
{
tree[u].llen = tree[u<<1].llen;
tree[u].rlen = tree[u<<1|1].rlen;
if ( tree[u<<1].llen == tree[u<<1].r - tree[u<<1].l + 1 )
tree[u].llen = tree[u<<1].llen + tree[u<<1|1].llen;
if ( tree[u<<1|1].rlen == tree[u<<1|1].r - tree[u<<1|1].l + 1 )
tree[u].rlen = tree[u<<1].rlen + tree[u<<1|1].rlen;
}
void update ( int u , int x , int v)
{
int l = tree[u].l , r = tree[u].r;
if ( l == r )
{
tree[u].llen = tree[u].rlen = v;
return;
}
int mid = l + r >> 1;
if ( x > mid ) update ( u<<1|1 , x , v );
else update ( u<<1 , x , v );
push_up ( u );
}
int query ( int u , int x )
{
int l = tree[u].l , r = tree[u].r;
if ( r-l+1 == tree[u].llen )
return r-l+1;
if ( l == r )
return tree[u].llen;
int mid = l + r >> 1;
if ( x > mid )
{
if ( tree[u<<1|1].l + tree[u<<1|1].llen > x )
return query ( u<<1|1 , x ) + tree[u<<1].rlen;
else return query ( u<<1|1 , x );
}
else
{
if ( tree[u<<1].r - tree[u<<1].rlen < x )
return query ( u<<1 , x ) + tree[u<<1|1].llen;
else return query ( u<<1 , x );
}
}
int main ( )
{
while ( ~scanf ( "%d%d" , &n , &m ) )
{
build ( 1 , 1 , n );
while ( !stk.empty() ) stk.pop();
for ( int i = 0 ; i < m ; i++ )
{
scanf ( "%s" , s );
if ( s[0] == 'D' )
{
scanf ( "%d" , &a );
update ( 1 , a , 0 );
stk.push ( a );
}
else if ( s[0] == 'Q' )
{
scanf ( "%d" , &a );
printf ( "%d\n" , query ( 1 , a ) );
}
else
{
update ( 1 , stk.top() , 1 );
stk.pop ( );
}
}
}
}