(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的个数,这里需要用到离线操作
求区间中未出现的最小整数
我们发现,我们如果将查询区间后的数组元素更新在线段树上后,线段树的查询就会变得复杂,所以这里也需要用到离线操作。
代码实现:
static long mod = (int) 1e9 + 7;
static int MAXN = 300005;
static int[] cnt = new int[MAXN];
static int[] a = new int[MAXN];
static int[] leaf = new int[MAXN];
public static void main(String[] args) throws IOException {
FastScanner f = new FastScanner();
PrintWriter w = new PrintWriter(System.out);
for (int i = 1; i <= n; i++) {
if (a[i] > n) a[i] = n + 1;
SegTree seg = new SegTree();
PriorityQueue<Pair> pairs = new PriorityQueue<Pair>(new Comparator<Pair>() {
public int compare(Pair o1, Pair o2) {
for (int i = 0; i < m; i++) {
pairs.add(new Pair(x, y, i));
PriorityQueue<Res> res = new PriorityQueue<>(new Comparator<Res>() {
public int compare(Res o1, Res o2) {
for (int i = 1; i <= n; i++) {
seg.change_leaf(i, a[i]);
while(!pairs.isEmpty() && pairs.peek().r == i){
res.add(new Res(-1, tt, cur.id, cur.r));
res.add(new Res(1, tt, cur.id, cur.l - 1));
for (int i = 1; i <= n; i++) {
while(!res.isEmpty() && res.peek().pos == i){
ans[cur.id] += cur.type * sum(cur.num);
for (int i = 0; i < m; i++) {
public static void update(int x){
for (int i = x; i <= n; i += i & - i) {
public static int sum(int x){
public Res(int type, int num, int id, int pos) {
public static class Pair{
public Pair(int l, int r, int id) {
public static class Node{
public static class SegTree{
Node[] t = new Node[4 * MAXN];
for (int i = 0; i < 4 * MAXN; i++) {
public void build(int root, int l, int r){
build(root << 1, l, (l + r) >> 1);
build(root << 1 | 1, (l + r) >> 1 | 1, r);
public void change_leaf (int id, int num){
int root = leaf[num] >> 1;
t[root].pos = Math.min(t[root << 1].pos, t[root << 1 | 1].pos);
while (t[root].l != t[root].r){
if (t[root << 1].pos >= l){
private static class FastScanner {
final private int BUFFER_SIZE = 1 << 16;
private DataInputStream din;
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 {
while (c <= ' ') c = read();
boolean neg = (c == '-');
do ret = (short) (ret * 10 + c - '0');
while ((c = read()) >= '0' && c <= '9');
if (neg) return (short) -ret;
private int nextInt() throws IOException {
while (c <= ' ') c = read();
boolean neg = (c == '-');
do ret = ret * 10 + c - '0';
while ((c = read()) >= '0' && c <= '9');
public long nextLong() throws IOException {
while (c <= ' ') c = read();
boolean neg = (c == '-');
do ret = ret * 10 + c - '0';
while ((c = read()) >= '0' && c <= '9');
private char nextChar() throws IOException {
while (c <= ' ') c = read();
private String nextString() throws IOException {
StringBuilder ret = new StringBuilder();
while (c <= ' ') c = read();
} while ((c = read()) > ' ');
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++];