目录
小红的区间删除:
题目大意:
思路解析:
逆序对可以使用任意分治算法来求得,但是我们要删除一段连续区间,所以这里可以采用线段树或者两个数组进行逆序对的查询。
然后题目要求在删除一段连续区间后,剩余数组的逆序对大于等于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());
}
}
}