CF1404C. Fixed Point Removal

该博客探讨了一种数组处理问题,涉及在限定操作下找到最大可删除元素数量的策略。文章介绍了如何通过二分搜索和树状数组来确定每个元素的可删除范围,并在面对查询时使用离线处理和树状数组优化算法。内容涵盖了算法设计和实现细节,适合对数据结构和算法感兴趣的读者。
摘要由CSDN通过智能技术生成

https://codeforces.com/contest/1404/problem/C

C. Fixed Point Removal

time limit per test

4 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

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

Copy

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

Copy

5
11
6
1
0

input

Copy

5 2
1 4 1 2 4
0 0
1 0

output

Copy

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 5.

 

第一步先求出每个元素会能被删除时的最短子数组的左边界,得到区间[Li,Ri]。此时题目转化为每次查询的区间[QLi,QRi]包含多少个区间[Li,Ri]。后一步可用离线操作+树状数组得到结果。第一步可用二分+树状数组得到结果,其中每个左边界都是初始ai=i的位置。

import java.util.*;
import java.io.*;

public class Main {
    public static void main(String args[]) {new Main().run();}

    FastReader in = new FastReader();
    PrintWriter out = new PrintWriter(System.out);
    void run(){
        work();
        out.flush();
    }
    long mod=998244353;
    long gcd(long a,long b) {
        return a==0?b:gcd(b%a,a);
    }
    final long inf=Long.MAX_VALUE/3;
    int[] S;
    int[] S2;
    void work(){
        int n=ni(),q=ni();
        int[] A=new int[n+1];
        for(int i=1;i<=n;i++){
            A[i]=ni();
        }
        S=new int[n+1];
        S2=new int[n+1];
        int[] pre=new int[n+1];
        for(int i=1;i<=n;i++){
            if(A[i]==i){
                pre[i]=i;
                add(i,S2);
            }else if(i>A[i]){
                int l=0,r=i;
                while(l<r){
                    int m=(l+r)/2;
                    int query = query(Math.max(m, 1), i, S2);
                    if(query>=i-A[i]){
                        l=m+1;
                    }else{
                        r=m;
                    }
                }
                if(l>1){
                    add(l-1,S2);
                    pre[i]=l-1;
                }
            }
        }
        ArrayList<int[]> list=new ArrayList<>();
        for(int i=1;i<=n;i++){
            if(pre[i]!=0){
                list.add(new int[]{pre[i],i});
            }
        }
        Collections.sort(list,(a1,a2)->a1[1]-a2[1]);
        int[][] B=new int[q][];
        for(int i=0;i<q;i++){
            B[i]=new int[]{ni()+1,n-ni(),i};
        }
        int[] ret=new int[q];
        Arrays.sort(B,(a1,a2)->a1[1]-a2[1]);
        for(int i=0,j=0;i<q;i++){
            while(j<list.size()&&list.get(j)[1]<=B[i][1]){
                add(list.get(j)[0],S);
                j++;
            }
            int idx=B[i][2];
            ret[idx]=query(B[i][0],B[i][1],S);
        }
        for(int r:ret){
            out.println(r);
        }
    }

    int lowbit(int f){
        return f&-f;
    }

    void add(int idx,int[] S){
        for(;idx<S.length;idx+=lowbit(idx)){
            S[idx]++;
        }
    }

    int query(int s,int e,int[] S){
        return query(e,S)-query(s-1,S);
    }
    int query(int idx,int[] S){
        int ret=0;
        for(;idx>0;idx-=lowbit(idx)){
            ret+=S[idx];
        }
        return ret;
    }

    //input
    @SuppressWarnings("unused")
    private ArrayList<Integer>[] ng(int n, int m) {
        ArrayList<Integer>[] graph=(ArrayList<Integer>[])new ArrayList[n];
        for(int i=0;i<n;i++) {
            graph[i]=new ArrayList<>();
        }
        for(int i=1;i<=m;i++) {
            int s=in.nextInt()-1,e=in.nextInt()-1;
            graph[s].add(e);
            graph[e].add(s);
        }
        return graph;
    }

    private ArrayList<long[]>[] ngw(int n, int m) {
        ArrayList<long[]>[] graph=(ArrayList<long[]>[])new ArrayList[n];
        for(int i=0;i<n;i++) {
            graph[i]=new ArrayList<>();
        }
        for(int i=1;i<=m;i++) {
            long s=in.nextLong()-1,e=in.nextLong()-1,w=in.nextLong();
            graph[(int)s].add(new long[] {e,w});
            graph[(int)e].add(new long[] {s,w});
        }
        return graph;
    }

    private int ni() {
        return in.nextInt();
    }

    private long nl() {
        return in.nextLong();
    }

    private String ns() {
        return in.next();
    }

    private long[] na(int n) {
        long[] A=new long[n];
        for(int i=0;i<n;i++) {
            A[i]=in.nextLong();
        }
        return A;
    }
    private int[] nia(int n) {
        int[] A=new int[n];
        for(int i=0;i<n;i++) {
            A[i]=in.nextInt();
        }
        return A;
    }
}

class FastReader
{
    BufferedReader br;
    StringTokenizer st;

    public FastReader()
    {
        br=new BufferedReader(new InputStreamReader(System.in));
    }


    public String next()
    {
        while(st==null || !st.hasMoreElements())//回车,空行情况
        {
            try {
                st = new StringTokenizer(br.readLine());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return st.nextToken();
    }

    public int nextInt()
    {
        return Integer.parseInt(next());
    }

    public long nextLong()
    {
        return Long.parseLong(next());
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值