牛客周赛round 38 --- G 小红的区间删除 -- 题解

目录

小红的区间删除:

题目大意:

思路解析:

代码实现:


 

小红的区间删除:

题目大意:

思路解析:

        逆序对可以使用任意分治算法来求得,但是我们要删除一段连续区间,所以这里可以采用线段树或者两个数组进行逆序对的查询。

        然后题目要求在删除一段连续区间后,剩余数组的逆序对大于等于k的删除方案数,如果原始数组就小于k,那么方案数为0,否则我们枚举左端点,然后看哪些区间能够进行删除。

        那我们怎么查询删除 [l,r] 这个区间后,逆序对剩下多少个呢,假设我们得到了 删除[l,r-1]区间的逆序对数量, 那么删除r后,逆序对就会减少 s个,其中有a[r]作为逆序对左端点的情况,也有a[r]作为右端点的情况,那我们可以发现我们应该维护两个线段树,一个是 [1,r-1]的信息一个是[r+1,n]的信息,利用这两个线段树的信息就可以查询删除任意区间的剩余逆序对数量了。

代码实现:

import java.io.*;
import java.math.BigInteger;
import java.util.*;

public class Main {
    static int inf = (int) 2e7;
    public static void main(String[] args) throws IOException {

        int t = 1;
        while (t > 0) {
            solve();
            t--;
        }

        w.flush();
        w.close();
        br.close();
    }

    static int maxN = (int) 1e6 + 5;
    static int N = (int) 1e6;
    public static void solve() {
        int n = f.nextInt();
        long k = f.nextLong();
        long sum = 0;
        int[] a = new int[n];
        SegTree tree = new SegTree();
        tree.build(1, 1, N);
        for (int i = 0; i < n; i++) {
            a[i] = f.nextInt();
            sum += tree.sum(1, a[i]+1, N, 1);
            tree.change(1, a[i], 1, 1);
        }
        if (sum < k) {w.println(0);return;}
        else {
            int r = 0;
            long ans = 1;
            for (int l = 0; l < n; l++) {
                if (r < l) r = l;
                while (r < n){
                    int lx = tree.sum(1, a[r]+1, N, 2);
                    int rx = tree.sum(1, 1, a[r]-1, 1);
                    if (sum - lx - rx < k) break;
                    sum -= lx + rx;
                    tree.change(1, a[r], 1, -1);
                    r++;
                }
                ans+=r-l;
                tree.change(1, a[l], 2, 1);
                int lx = tree.sum(1, a[l]+1, N, 2);
                int rx = tree.sum(1, 1, a[l]-1, 1);
                if (l==r) continue;
                sum += lx + rx;
            }
            w.print(ans);
        }
    }

    static class SegTree{
        Node[] t = new Node[maxN * 4];
        public SegTree(){
            for (int i = 0; i < maxN * 4; i++) {
                t[i] = new Node();
            }
        }
        void build(int root, int l, int r){
            t[root].l = l;
            t[root].r = r;
            if (l == r) return;
            int ch = root << 1;
            int mid = (l + r) >> 1;
            build(ch, l, mid);
            build(ch|1, mid+1, r);
        }
        void update(int root){
            int ch = root << 1;
            t[root].sum[0] = t[ch].sum[0] + t[ch|1].sum[0];
            t[root].sum[1] = t[ch].sum[1] + t[ch|1].sum[1];
        }
        void change(int root, int x, int op, int val){
            if (t[root].l == x && t[root].r == x){
                t[root].sum[op - 1] += val;
                return;
            }
            int ch = root << 1;
            int mid = (t[root].l + t[root].r) >> 1;
            if (x <= mid) change(ch, x, op, val);
            else change(ch|1, x, op, val);
            update(root);
        }
        int sum(int root, int l, int r, int op){
            if (l > r) return 0;
            if (t[root].l == l && t[root].r == r){
                return t[root].sum[op - 1];
            }
            int ch = root << 1;
            int mid = (t[root].l + t[root].r) >> 1;
            if (r <= mid) return sum(ch, l, r, op);
            else if (l > mid) return sum(ch|1, l, r, op);
            else{
                int ans = sum(ch, l, mid, op);
                ans += sum(ch|1, mid+1, r, op);
                return ans;
            }
        }

    }


    public static class Node{
        int l,r;
        int[] sum = new int[2];

    }

    static PrintWriter w = new PrintWriter(new OutputStreamWriter(System.out));
    static Input f = new Input(System.in);
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    static class Input {
        public BufferedReader reader;
        public StringTokenizer tokenizer;

        public Input(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            tokenizer = null;
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        public String nextLine() {
            String str = null;
            try {
                str = reader.readLine();
            } catch (IOException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
            return str;
        }

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

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

        public Double nextDouble() {
            return Double.parseDouble(next());
        }

        public BigInteger nextBigInteger() {
            return new BigInteger(next());
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Studying~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值