题目链接:点击打开链接
题目大意:给出n个格子,三种操作,D k:消除第k个格子,R:恢复最后一次消除的格子,Q k:问和k相连的最长连续序列。
求最长连续序列,线段树统计每段中被消除的最大点和最小点,更新点k,查询段[1,k][k,n],然后相减得到结果
#include <cstdio>
#include <cstring>
#include <stack>
#include <algorithm>
using namespace std ;
#define INF 0x3f3f3f3f
int cl_max[500000] , cl_min[500000] ;
stack <int> sta ;
void push_up(int rt) {
cl_max[rt] = max(cl_max[rt<<1],cl_max[rt<<1|1]) ;
cl_min[rt] = min(cl_min[rt<<1],cl_min[rt<<1|1]) ;
}
void update(int k,int flag,int l,int r,int rt) {
if(l == r) {
if( flag == -1 )
cl_max[rt] = 0 , cl_min[rt] = INF ;
else
cl_max[rt] = cl_min[rt] = k ;
return ;
}
if( k <= (l+r)/2 )
update(k,flag,l,(l+r)/2,rt<<1) ;
else
update(k,flag,(l+r)/2+1,r,rt<<1|1) ;
push_up(rt) ;
}
int query1(int ll,int rr,int l,int r,int rt) {
if( rr < l || ll > r ) return 0 ;
if( ll <= l && rr >= r ) return cl_max[rt] ;
return max(query1(ll,rr,l,(l+r)/2,rt<<1),query1(ll,rr,(l+r)/2+1,r,rt<<1|1)) ;
}
int query2(int ll,int rr,int l,int r,int rt) {
if( rr < l || ll > r ) return INF ;
if( ll <= l && rr >= r ) return cl_min[rt] ;
return min(query2(ll,rr,l,(l+r)/2,rt<<1),query2(ll,rr,(l+r)/2+1,r,rt<<1|1)) ;
}
int main() {
int n , m , k , min1 , max1 ;
char s[5] ;
while( scanf("%d %d", &n, &m) !=EOF ) {
memset(cl_max,0,sizeof(cl_max)) ;
memset(cl_min,INF,sizeof(cl_min)) ;
while( !sta.empty() ) sta.pop() ;
while( m-- ) {
scanf("%s", s) ;
if( s[0] == 'D' ) {
scanf("%d", &k) ;
sta.push(k) ;
update(k,1,1,n,1) ;
}
else if( s[0] == 'Q' ) {
scanf("%d", &k) ;
max1 = query1(1,k,1,n,1) ;
min1 = query2(k,n,1,n,1) ;
//printf("Q--> max1 = %d min1 = %d\n", max1 , min1) ;
if( min1 == INF ) min1 = n+1 ;
if( max1 == min1 )
printf("0\n") ;
else
printf("%d\n", min1-1-max1 ) ;
}
else{
k = sta.top() ;
sta.pop() ;
update(k,-1,1,n,1) ;
}
}
}
return 0 ;
}