思路:线段树基本操作。
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int AX = 1e6+6;
LL s[AX<<2];
LL a[AX<<2];
LL b[AX<<2];
void pushUp( int rt ){
s[rt] = s[rt<<1] + s[rt<<1|1];
a[rt] = max( a[rt<<1] , a[rt<<1|1] );
b[rt] = min( b[rt<<1] , b[rt<<1|1] );
}
void update( int site , int v , int l , int r , int rt ){
if( l == r ){
s[rt] = v;
a[rt] = v;
b[rt] = v;
return;
}
int mid = ( l + r ) >> 1;
if( site <= mid ) update( site , v , l , mid , rt << 1 );
if( mid < site ) update( site , v , mid + 1 , r , rt << 1 | 1 );
pushUp(rt);
}
LL query_SUM( int L , int R , int l , int r , int rt ){
if( L <= l && R >= r ){
return s[rt];
}
int mid = ( l + r ) >> 1;
LL sum = 0LL;
if( L <= mid ){
sum += query_SUM( L , R , l , mid , rt << 1 );
}
if( mid < R ){
sum += query_SUM( L , R , mid + 1 , r , rt << 1 | 1 );
}
return sum ;
}
int query_MAX( int L , int R , int l , int r , int rt ){
if( L <= l && R >= r ) return a[rt];
int ans = -INF;
int mid = ( l + r ) >> 1;
if( L <= mid) ans = max( ans , query_MAX( L , R , l , mid , rt << 1 ) ) ;
if( R > mid ) ans = max( ans , query_MAX( L , R , mid + 1 , r , rt << 1 | 1 ) ) ;
return ans ;
}
int query_MIN( int L ,int R , int l , int r , int rt ){
if( L <= l && R >= r ) return b[rt];
int ans = INF;
int mid = ( l + r ) >> 1 ;
if( L <= mid ) ans = min( ans , query_MIN( L , R , l , mid , rt << 1 ));
if( R > mid ) ans = min( ans , query_MIN( L , R , mid + 1 , r , rt << 1 | 1 ));
return ans ;
}
int main(){
int n , m;
memset( s , 0 , sizeof(s) );
memset( a , 0 , sizeof(a) );
memset( b , 0 , sizeof(b) );
scanf("%d%d",&n,&m);
int op;
int x, y;
while( m-- ){
scanf("%d",&op);
if( !op ){
scanf("%d%d",&x,&y);
update( x , y , 1 , n , 1 );
}else{
int L , R;
scanf("%d%d",&L,&R) ;
int maxn = query_MAX(L,R,1,n,1);
int minus = query_MIN(L,R,1,n,1);
LL sum = query_SUM(L,R,1,n,1);
printf("%lld\n",sum-maxn-minus);
}
}
return 0 ;
}
Code:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
int n, m ;
const int AX = 1e6+6;
LL s[AX<<2];
int lazy[AX<<2];
LL res ;
void pushUp( int rt ){
s[rt] = s[rt<<1] + s[rt<<1|1];
return ;
}
void pushDown( int rt , int L , int R ){
if( lazy[rt] ){
int mid = ( L + R ) >> 1 ;
s[rt<<1] += ( mid - L + 1 ) * lazy[rt] ;
s[rt<<1|1] += ( R - mid ) * lazy[rt];
lazy[rt<<1] += lazy[rt];
lazy[rt<<1|1] += lazy[rt];
lazy[rt] = 0;
}
return ;
}
void update( int L , int R , int v , int l , int r , int rt ){
if( L <= l && R >= r ){
s[rt] += ( r - l + 1 ) * v;
lazy[rt] += v;
return;
}
pushDown(rt,l,r);
int mid = ( l + r ) >> 1;
if( L <= mid ) update( L , R , v , l ,mid , rt << 1 );
if( R > mid ) update( L , R , v , mid + 1 , r , rt << 1 | 1 );
pushUp(rt);
}
LL Query( int L , int R , int l , int r , int rt ){
if( L <= l && R >= r ){
//res += s[rt];
return s[rt];
}
pushDown(rt,l,r);
int mid = ( l + r ) >> 1 ;
LL res = 0;
if( L <= mid ) res += Query( L , R , l , mid , rt << 1 );
if( R > mid ) res += Query( L , R , mid + 1, r , rt << 1 | 1 );
return res;
}
int main(){
scanf("%d%d",&n,&m);
memset( lazy , 0 , sizeof(lazy) );
memset( s , 0 , sizeof(s) );
while( m -- ){
int op ;
int L , R , v;
scanf("%d%d%d%d",&op,&L,&R,&v);
if( op == 0 ){
update( L , R , v , 1 , n , 1 );
}else{
res = 0;
LL res = Query( L , R , 1 , n , 1 );
printf("%lld\n",res);
}
}
return 0;
}
思路:
假设每个Ci = i , bn最大为n+1.
对于每个Ci , 相当于询问b(i-ci) – b(i-1)区间内最小未出现的数。
我们可以设s[x] 为x最后出现的位置。对于每个Ci,我们可以得到左区间 i - Ci;
s[1] = 0 , 其他位置初始化-1(其他值都未出现过,所以都满足s[x] < i - ci )
凡是s【x】< i - Ci 的x均未在区间内出现过,那么我们只要找出最小的x,满足:
s[x] < i - ci即可。
可以用线段树维护s[x] ,1 <= x < n+1 ;区间的最小值。
每次给出左区间 i -ci ,就从最大的区间查询,如果左子树的最小值>=i-ci,就递归访问右子树,否则访问左子树。
最终区间长度为1时,l(或者r)即为答案。
Code:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
const int AX = 1e6+6;
int s[AX<<2];
int res[AX];
int n;
int tot ;
void pushUp( int rt ){
s[rt] = min( s[rt<<1] , s[rt<<1|1] ) ;
return ;
}
void update( int site , int v , int l , int r , int rt ){
if( l == r ){
s[rt] = v;
return;
}
int mid = ( l + r ) >> 1 ;
if( site <= mid ) update( site , v , l , mid , rt << 1 );
if( site > mid ) update( site , v , mid + 1 , r , rt << 1 | 1 );
pushUp(rt);
}
int query( int L , int R , int l , int r , int rt ){
if( L <= l && R >= r ){
return s[rt];
}
int mid = ( l + r ) >> 1 ;
int res = INF;
if( L <= mid ) res = min( res , query( L , R , l , mid , rt << 1 ) );
if( R > mid ) res = min( res , query( L , R , mid + 1 , r , rt << 1 | 1 ) );
return res;
}
int solve( int l , int r , int rt , int v ){
if( l == r ){
return l;
}
int mid = ( l + r ) >> 1;
if( s[rt<<1] >= v ){
return solve( mid + 1 , r , rt << 1 | 1, v );
}else{
return solve( l , mid , rt << 1 , v );
}
}
int main(){
scanf("%d",&n);
int x;
tot = 0;
memset( s, -1 , sizeof(s) );
update( 1 , 0 , 1 , n + 1 , 1 );
for( int i = 1 ; i <= n ; i++ ){
scanf("%d",&x);
int v = i - x ;
res[i] = solve( 1 , n + 1 , 1 , v );
update( res[i] , i , 1 , n + 1 , 1 );
}
for( int i = 1 ; i < n ; i++ ){
printf("%d ",res[i]);
}printf("%d\n",res[n]);
return 0;
}
思路:
线段树+二分答案
结果只要求a[k]的值,并且a数列是1-n的一个全排列,那么可以二分答案。
假设mid为答案,将大于mid的设为1,小于等于的设为0
当对【L,R】区间进行排序时,
1.先求出区间内1的个数。
2.区间全置为0.
3.升序排序时,将最后c个数 ( 【R-c+1,R】 ) 置为1.
4.降序排序时,将前c个数( 【 L,L + c - 1 】)置为1.
所有操作进行结束后,如果【k,k】== 1 说明a【k】> mid ( -> li = mid + 1 ) ,为0说明 a[k] < mid ( -> ri = mid ) .
Code:
#include <bits/stdc++.h>
using namespace std;
const int AX = 1e5+66;
int lazy[AX<<2];
int s[AX<<2];
int a[AX];
int op[AX];
int l[AX];
int r[AX];
int n,k;
int tot;
void pushDown( int rt , int L , int R ){
if( lazy[rt] != -1 ){
int mid = ( L + R ) >> 1 ;
s[rt<<1] = ( mid - L + 1 ) * lazy[rt] ;
s[rt<<1|1] = ( R - mid ) * lazy[rt];
lazy[rt<<1] = lazy[rt];
lazy[rt<<1|1] = lazy[rt];
lazy[rt] = -1;
}
return ;
}
void pushUp( int rt ){
s[rt] = s[rt<<1] + s[rt<<1|1];
return ;
}
void build( int l , int r , int rt , int v ){
lazy[rt] = -1;
if( l == r ){
s[rt] = ( a[l] > v ) ;
return ;
}
int mid = ( l + r ) >> 1 ;
build( l , mid , rt << 1 , v );
build( mid + 1 , r , rt << 1 | 1 , v);
pushUp(rt);
}
void update( int L , int R , int v , int l , int r , int rt ){
if( L <= l && R >= r ){
s[rt] = v * ( r - l + 1 );
lazy[rt] = v;
return;
}
pushDown(rt,l,r);
int mid = ( l + r ) >> 1;
if( L <= mid ) update( L , R , v , l , mid , rt << 1 );
if( R > mid ) update( L , R , v , mid + 1 , r , rt << 1 | 1);
pushUp(rt);
}
int query( int L , int R , int l , int r , int rt ){
if( L <= l && R >= r ){
return s[rt];
}
pushDown(rt,l,r);
int ans = 0 ;
int mid = ( l + r ) >> 1;
if( L <= mid ) ans += query( L , R , l , mid, rt << 1 );
if( R > mid ) ans += query( L , R , mid + 1, r , rt << 1 | 1 );
return ans ;
}
int main(){
scanf("%d%d",&n,&k);
for( int i = 1 ; i <= n ; i++ ){
scanf("%d",&a[i]);
}
int m ;
scanf("%d",&m);
for( int i = 0 ; i < m ; i++ ){
scanf("%d%d%d",&op[i],&l[i],&r[i]);
}
int li = 1 , ri = n ;
while( li < ri ){
int mid = ( li + ri ) >> 1 ;
build( 1 , n , 1 , mid );
for( int i = 0 ; i < m ; i++ ){
int L = l[i];
int R = r[i];
int c = query( L , R , 1 , n , 1 );
update( L , R , 0 , 1 , n , 1 );
if( op[i] ){
if( L <= L + c - 1 ){
update( L , L + c - 1 , 1 , 1, n , 1 );
}
}else{
if( R - c + 1 <= R ){
update( R - c + 1 , R , 1 , 1 , n , 1 );
}
}
}
if( query( k , k , 1 , n , 1 ) ){
li = mid + 1 ;
}else ri = mid ;
}
printf("%d\n",li);
return 0 ;
}