little w and Discretization --- 题解 (线段树好题)

目录

little w and Discretization --- 题解 (线段树好题)

题目大意:

思路解析:

代码实现:


 

little w and Discretization --- 题解 (线段树好题)

题目大意:

        

思路解析:

         离散化数组满足以下要求:

             (1) 保留原数组的大小关系, 即当a[i] > [j], 有b[i]>b[j],当a[i]=a[j]有b[i]=b[j],当a[i]<a[j]有b[i]<b[j]

               (2)b数组有正整数构成

                (3)在满足以上两点情况下,b数组的每个元素都要求尽可能小

        这道题要求那么将 al -- ar这个区间的元素进行离散化,离散化后将有多少个元素与原来不同。这个答案对于每个相同的数组是相同的,例如 1 2 3 5 6 7一定会离散化为1 2 3 4 5 6,可以发现只要当数组中有元素大于数组未出现的最小整数 ,那么这些元素离散化后一定与原来的元素不同。则问题转化为这个查询区间中最小未出现的元素为那个,并且大于它的元素有多少个。因为我们知道区间长度,那么答案可以转化为 len - cnt, cnt表示小于等于它的元素有多少个。

cnt可以用数组数组查询区间和来解决,那么难点变为了,如何求区间中未出现的最小整数。

 cnt还有个小细节,需要注意,假如我们查询画框数组,那么未出现的最小整数,小于等于它的个数为1,但是我们查询某个区间小于等于的数是较复杂的,我们可以转化为 求 1-2这个区间小于等于2的个数和1-7这个区间小于等于2的个数,这里需要用到离线操作

        

求区间中未出现的最小整数

 

我们发现,我们如果将查询区间后的数组元素更新在线段树上后,线段树的查询就会变得复杂,所以这里也需要用到离线操作。

代码实现:

        

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


public class Main {
    static long mod = (int) 1e9 + 7;
    static int base = 131;
    static int MAXN = 300005;
    static int[] cnt = new int[MAXN];
    static int[] a = new int[MAXN];
    static int[] leaf = new int[MAXN];
    static int n;



    public static void main(String[] args) throws IOException {
        FastScanner f = new FastScanner();
        PrintWriter w = new PrintWriter(System.out);
        n = f.nextInt();
        for (int i = 1; i <= n; i++) {
            a[i] = f.nextInt();
            if (a[i] > n) a[i] = n + 1;
        }
        SegTree seg = new SegTree();
        seg.build(1, 1, n);
        int m = f.nextInt();
        PriorityQueue<Pair> pairs = new PriorityQueue<Pair>(new Comparator<Pair>() {
            @Override
            public int compare(Pair o1, Pair o2) {
                return o1.r - o2.r;
            }
        });
        int[] ans = new int[m];
        for (int i = 0; i < m; i++) {
            int x = f.nextInt();
            int y = f.nextInt();
            ans[i] = (y - x + 1);
            pairs.add(new Pair(x, y, i));
        }
        PriorityQueue<Res> res = new PriorityQueue<>(new Comparator<Res>() {
            @Override
            public int compare(Res o1, Res o2) {
                return o1.pos - o2.pos;
            }
        });
        for (int i = 1; i <= n; i++) {
            seg.change_leaf(i, a[i]);
           while(!pairs.isEmpty() && pairs.peek().r == i){
               Pair cur = pairs.poll();
               int tt = seg.mex(cur.l);
               res.add(new Res(-1, tt, cur.id, cur.r));
               if (cur.l != 1){
                   res.add(new Res(1, tt, cur.id, cur.l - 1));
               }
           }
        }
        for (int i = 1; i <= n; i++) {
            update(a[i]);
            while(!res.isEmpty() && res.peek().pos == i){
                Res cur = res.poll();
                ans[cur.id] += cur.type * sum(cur.num);
            }
        }
        for (int i = 0; i < m; i++) {
            w.println(ans[i]);
        }
        w.flush();
        w.close();

    }

    public static void update(int x){
        for (int i = x; i <= n; i += i & - i) {
            cnt[i] += 1;
        }
    }

    public static int sum(int x){
        int  res = 0;
        while (x > 0){
            res += cnt[x];
            x -= x & -x;
        }
        return res;
    }
    public static class Res{
        int type, num, id, pos;

        public Res(int type, int num, int id, int pos) {
            this.type = type;
            this.num = num;
            this.id = id;
            this.pos = pos;
        }
    }
    public static class Pair{
        int l, r, id;

        public Pair(int l, int r, int id) {
            this.l = l;
            this.r = r;
            this.id = id;
        }
    }
    public static class Node{
        int l;
        int r;
        int pos;
    }
    public static class SegTree{
        Node[] t = new Node[4 * MAXN];

        public SegTree() {
            for (int i = 0; i < 4 * MAXN; i++) {
                t[i] = new Node();
            }
        }

        public void build(int root, int l, int r){
            t[root].l = l;
            t[root].r = r;
            if (l != r){
                build(root << 1, l, (l + r) >> 1);
                build(root << 1 | 1,  (l + r) >> 1 | 1, r);
            }else {
                t[root].pos = 0;
                leaf[l] = root;
            }
        }

        public void change_leaf (int id, int num){
            t[leaf[num]].pos = id;
            int root = leaf[num] >> 1;
            while (root > 0){
                t[root].pos = Math.min(t[root << 1].pos, t[root << 1 | 1].pos);
                root >>= 1;
            }
        }

        public int mex(int l){
            int root = 1;
            while (t[root].l != t[root].r){
                if (t[root << 1].pos >= l){
                    root = root << 1 | 1;
                }else {
                    root = root << 1;
                }
            }
            return t[root].l - 1;
        }
    }



    private static class FastScanner {
        final private int BUFFER_SIZE = 1 << 16;
        private DataInputStream din;
        private byte[] buffer;
        private int bufferPointer, bytesRead;

        private FastScanner() throws IOException {
            din = new DataInputStream(System.in);
            buffer = new byte[BUFFER_SIZE];
            bufferPointer = bytesRead = 0;
        }

        private short nextShort() throws IOException {
            short ret = 0;
            byte c = read();
            while (c <= ' ') c = read();
            boolean neg = (c == '-');
            if (neg) c = read();
            do ret = (short) (ret * 10 + c - '0');
            while ((c = read()) >= '0' && c <= '9');
            if (neg) return (short) -ret;
            return ret;
        }

        private int nextInt() throws IOException {
            int ret = 0;
            byte c = read();
            while (c <= ' ') c = read();
            boolean neg = (c == '-');
            if (neg) c = read();
            do ret = ret * 10 + c - '0';
            while ((c = read()) >= '0' && c <= '9');
            if (neg) return -ret;
            return ret;
        }

        public long nextLong() throws IOException {
            long ret = 0;
            byte c = read();
            while (c <= ' ') c = read();
            boolean neg = (c == '-');
            if (neg) c = read();
            do ret = ret * 10 + c - '0';
            while ((c = read()) >= '0' && c <= '9');
            if (neg) return -ret;
            return ret;
        }

        private char nextChar() throws IOException {
            byte c = read();
            while (c <= ' ') c = read();
            return (char) c;
        }

        private String nextString() throws IOException {
            StringBuilder ret = new StringBuilder();
            byte c = read();
            while (c <= ' ') c = read();
            do {
                ret.append((char) c);
            } while ((c = read()) > ' ');
            return ret.toString();
        }

        private void fillBuffer() throws IOException {
            bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
            if (bytesRead == -1) buffer[0] = -1;
        }

        private byte read() throws IOException {
            if (bufferPointer == bytesRead) fillBuffer();
            return buffer[bufferPointer++];
        }
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Studying~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值