题解——A君的问题(a)(值域线段树)
题解——A君的问题(a)
这道题很水,但不要问ssw02为什么要在这时做一道B层的题
因为ssw02再换板子,而这道题就是二分值域线段树的裸题
感谢神犇SXK提供优质的模板参考
题目搬运
【题目描述】
A君来到了一个蛋糕店,蛋糕店有n个位置顺次摆放着若干蛋糕,从左到右位置编号依次递增。当有客人来的时候服务生会把有些位置的蛋糕打包给客人,也可能会在某个没有蛋糕的空位放上一个蛋糕。A君想知道在某一时刻从左数第k个蛋糕的位置。
【输入数据】
第一行一个正整数n,m,其中n表示位置数量,m表示客人的数量。第二行n个数为0或1,第i个数表示开始时没有蛋糕(0)或者有蛋糕(1)。接下来共m行每行俩个数p,k,其中k如上文,p表示第p个位置有无蛋糕的情况发生了变化。
【输出数据】
m行,每行一个数表示询问的结果,若不存在k个蛋糕则输出”-1”(不含引号)。
解题思路
没有思路,单点修改+单点查询(查询二分当前区间个数就可以了)
我只是想把它当个板子记一下而已(以前的太丑了)
AC code
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 500005 ;
int N , M , num , sum[ MAXN<<2 ] , a[ MAXN ] ;
inline int read(){
int s=0 ; char g=getchar() ;while(g>'9'||g<'0')g=getchar() ;
while(g>='0'&&g<='9')s=s*10+g-'0',g=getchar();return s ;
}
void build( int p , int l , int r ){
if( l == r ){
sum[ p ] = a[ l ] ; return ;
}
int mid = (l+r)>>1 ;
build( p<<1 , l , mid ) ;
build( p<<1|1 , mid+1 , r ) ;
sum[ p ] = sum[ p<<1 ] + sum[ p<<1 | 1 ] ;
}
void change_a( int p , int l , int r , int x , int v ){//和普通线段树没有区别
sum[ p ] += v ;
if( l==r )return ;
int mid = (l+r)>>1 ;
if( x <= mid )change_a( p<<1 , l , mid , x , v ) ;
else change_a( p<<1|1 , mid+1 , r , x , v ) ;
sum[ p ] = sum[ p<<1 ]+sum[ p<<1|1 ] ;
}
int ask( int p , int l , int r , int k ){
if( l == r )return l ;
int mid = (l+r)>>1 ;//二分个数,判断位置
if( sum[ p<<1 ] >= k )return ask( p<<1 , l , mid , k );
else return ask( p<<1|1 , mid+1 , r , k-sum[p<<1] );
}
int main(){
N = read() , M = read() ;
for( register int i = 1 ; i <= N ; ++i )
a[ i ] = read() , num += a[ i ] ;
build( 1 , 1 , N ) ;
while( M-- ){
int m1 = read() , m2 = read() ;
if( a[ m1 ] )
change_a( 1 , 1 , N , m1 , -1 ),a[m1]=0,num-- ;
else change_a( 1 , 1 , N , m1 , 1 ),a[m1]=1,num++ ;
if( m2 > num )printf("-1\n") ;
else printf("%d\n",ask( 1 , 1 , N , m2 ) ) ;
}
return 0 ;
}