题目
Let a1,…,ana1,…,an be an array of nn positive integers. In one operation, you can choose an index ii such that ai=iai=i, and remove aiai from the array (after the removal, the remaining parts are concatenated).
The weight of aa is defined as the maximum number of elements you can remove.
You must answer qq independent queries (x,y)(x,y): after replacing the xx first elements of aa and the yy last elements of aa by n+1n+1 (making them impossible to remove), what would be the weight of aa?
Input
The first line contains two integers nn and qq (1≤n,q≤3⋅1051≤n,q≤3⋅105) — the length of the array and the number of queries.
The second line contains nn integers a1a1, a2a2, ..., anan (1≤ai≤n1≤ai≤n) — elements of the array.
The ii-th of the next qq lines contains two integers xx and yy (x,y≥0x,y≥0 and x+y<nx+y<n).
Output
Print qq lines, ii-th line should contain a single integer — the answer to the ii-th query.
Examples
input
13 5 2 2 3 9 5 4 6 5 7 8 3 11 13 3 1 0 0 2 4 5 0 0 12
output
5 11 6 1 0
input
5 2 1 4 1 2 4 0 0 1 0
output
2 0
Note
Explanation of the first query:
After making first x=3x=3 and last y=1y=1 elements impossible to remove, aa becomes [×,×,×,9,5,4,6,5,7,8,3,11,×][×,×,×,9,5,4,6,5,7,8,3,11,×] (we represent 1414 as ×× for clarity).
Here is a strategy that removes 55 elements (the element removed is colored in red):
- [×,×,×,9,5,4,6,5,7,8,3,11,×][×,×,×,9,5,4,6,5,7,8,3,11,×]
- [×,×,×,9,4,6,5,7,8,3,11,×][×,×,×,9,4,6,5,7,8,3,11,×]
- [×,×,×,9,4,6,5,7,8,3,×][×,×,×,9,4,6,5,7,8,3,×]
- [×,×,×,9,4,5,7,8,3,×][×,×,×,9,4,5,7,8,3,×]
- [×,×,×,9,4,5,7,3,×][×,×,×,9,4,5,7,3,×]
- [×,×,×,9,4,5,3,×][×,×,×,9,4,5,3,×] (final state)
It is impossible to remove more than 55 elements, hence the weight is 55.
题解&思路
正解:考虑定义一个数组f[],f[i]表示为了让原数列的下标为i的点被消掉,x最大取的值
考虑:a[i]==i, f[i] = i - 1
a[i] > i , f[i] = -1 即a[i]永远不可能被消掉
a[i]<i , f[i] = 第i-a[i]大的f值,f只在前i-1个中找,可以发现,现在是要消掉前面的数i-a[i]个,那么如果找最大的f值那么前i-1个点只能被消一个,如果找次大f值前面的点只能消两个,所以找到第i-a[i]大的f值
然后将其映射到坐标系上,(i,f[i]),进行矩阵数点,而这个矩阵底边的横坐标属于当前可操作的l,r(即将l=x+1,r=n-y),纵坐标为x,因为fi>=x时才可以被消掉,定边的横坐标相同,纵坐标为正无穷
可用主席树做,也可以用树状数组求
代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 3e5 + 3;
int n , q , a[MAXN] , f[MAXN];
struct node{
int l , r , num ;
}tre[MAXN<<2];
inline void build( int i , int l , int r ){
tre[i].l = l , tre[i].r = r , tre[i].num = 0;
if( l == r ) return ;
int mid = ( l +r ) >> 1;
build( i << 1 , l , mid );
build( i << 1 | 1 , mid + 1 , r );
}
inline int query( int i , int s ){
if( tre[i].l == tre[i].r ){
return tre[i].l - 1;
}
if( s > tre[i<<1].num ){
s -= tre[i<<1].num;
return query( i << 1 | 1 , s );
}
else
return query( i << 1 , s );
}
inline void modify( int i , int l , int r ){
if( tre[i].l > r || tre[i].r < l ) return ;
if( tre[i].l == l && tre[i].r == r ){
tre[i].num ++;
return ;
}
modify( i << 1 , l , r );
modify( i << 1 | 1 , l , r );
tre[i].num = tre[i<<1].num + tre[i<<1|1].num;
}
struct edge{
int xs , xe , y , num;
int t;
friend bool operator < ( edge a , edge b ){
if( a.y != b.y ) return a.y < b.y;
return a.t < b.t;
}
}s[MAXN<<1];
int ncnt , ans[MAXN] , sum[MAXN];
int lowbit( int x ){ return x & -x;}
void change( int x , int delta ){
for( ; x <=n ; x += lowbit( x ) ) sum[x] += delta;
}
int query1( int l , int r ){
int tot = 0;
l --;
for( ; r ; r -= lowbit( r ) )
tot += sum[r];
for( ; l ; l -= lowbit( l ) )
tot -= sum[l];
return tot;
}
int main(){
scanf( "%d%d" , &n , &q );
build( 1 , 0 , n + 1 );
for( int i = 1 ; i <= n ; i ++ ){
scanf( "%d" , &a[i] );
if( a[i] == i ) f[i] = i -1;
if( a[i] > i ) f[i] = -1;
if( a[i] < i )
f[i] = query( 1 , tre[1].num - i + a[i] + 1 );
modify( 1 , f[i] + 1 , f[i] + 1 );
}
for( int i = 1 ; i <= n ; i += 1 ){
s[++ncnt].t = 1 , s[ncnt].xs = s[ncnt].xe = i , s[ncnt].y = f[i];
}
for( int i = 1 ; i <= q ; i ++ ){
int x , y;scanf( "%d%d" , &x , &y );
y = n - y;x ++;
s[++ncnt].t = 2 ;s[ncnt].xs = x , s[ncnt].xe = y , s[ncnt].y = n + 3 , s[ncnt].num = i;
s[++ncnt].t = 0 ;s[ncnt].xs = x , s[ncnt].xe = y , s[ncnt].y = x - 1 , s[ncnt].num = i;
}
sort( s + 1 , s + ncnt + 1) ;
for( int i = 1 ; i <= ncnt ; i ++ ){
if( s[i].t == 1 ){
if( s[i].y == -1 ) continue;
change( s[i].xe , 1 );
}
else if( s[i].t == 2 ){
int tot = query1( s[i].xs , s[i].xe );
ans[s[i].num] = tot - ans[s[i].num];
}
else{
int tot = query1( s[i].xs , s[i].xe );
ans[s[i].num] = tot;
}
}
for( int i = 1 ; i <= q ; i ++ )
printf( "%d\n" , ans[i] );
return 0;
}