目录
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++];
}
}
}