CF1404C - Fixed Point Removal

题目

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;
}

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值