2020 CCPC Wannafly Winter Camp Day1 - I. K小数查询(分块)

题目链接:K小数查询

题意:给你一个长度为$n$序列$A$,有$m$个操作,操作分为两种:

  • 输入$x,y,c$,表示对$i\in[x,y] $,令$A_{i}=min(A_{i},c)$
  • 输入$x,y,k$,表示询问区间$[x,y]$中的第$k$小数

思路:数据范围不是很大,可以分块来做,记录每个块已经更新过的最小值$imin[]$,询问时二分答案,然后求出$[x,y]$区间中小于等于$mid$的数的个数$cnt$,通过判断$cnt$与$k$的大小来改变$l,r$即可

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <vector>
#include <cmath>

using namespace std;

const int N = 100010;
const int INF = 0x3f3f3f3f;

int block, belong[N], num, l[N], r[N], imin[N];
int n, m, a[N];
vector<int> v[N];

void build()
{
    block = sqrt(n);
    num = n / block;
    if (n % block) num++;
    for (int i = 1; i <= num; i++)
        l[i] = (i - 1) * block + 1, r[i] = i * block;
    r[num] = n;
    for (int i = 1; i <= n; i++)
        belong[i] = (i - 1) / block + 1;
    for (int i = 1; i <= num; i++) {
        imin[i] = INF;
        for (int j = l[i]; j <= r[i]; j++)
            v[i].push_back(a[j]);
        sort(v[i].begin(), v[i].end());
    }
}

void reset(int x)
{
    v[x].clear();
    for (int i = l[x]; i <= r[x]; i++) {
        a[i] = min(a[i], imin[x]);
        v[x].push_back(a[i]);
    }
    sort(v[x].begin(), v[x].end());
}

void update(int x, int y, int c)
{
    int bl = belong[x], br = belong[y];
    if (bl == br) {
        for (int i = x; i <= y; i++)
            a[i] = min(a[i], c);
        reset(bl);
        return;
    }
    for (int i = x; i <= r[bl]; i++)
        a[i] = min(a[i], c);
    reset(bl);
    for (int i = l[br]; i <= y; i++)
        a[i] = min(a[i], c);
    reset(br);
    for (int i = bl + 1; i < br; i++)
        imin[i] = min(imin[i], c);
}

int query(int x, int y, int c)
{
    int bl = belong[x], br = belong[y], cnt = 0;
    if (bl == br) {
        for (int i = x; i <= y; i++)
            if (a[i] <= c || imin[bl] <= c) cnt++;
        return cnt;
    }
    for (int i = x; i <= r[bl]; i++)
        if (a[i] <= c || imin[bl] <= c) cnt++;
    for (int i = l[br]; i <= y; i++)
        if (a[i] <= c || imin[br] <= c) cnt++;
    for (int i = bl + 1; i < br; i++)
        if (imin[i] <= c) cnt = cnt + r[i] - l[i] + 1;
        else cnt = cnt + upper_bound(v[i].begin(), v[i].end(), c) - v[i].begin();
    return cnt;
}

int ask(int x, int y, int k)
{
    int l = -1000000000, r = 1000000000;
    while (l < r) {
        int mid = (l + r) / 2;
        if (query(x, y, mid) >= k) r = mid;
        else l = mid + 1;
    }
    return l;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    build();
    for (int i = 1; i <= m; i++) {
        int kd, x, y, c;
        scanf("%d%d%d%d", &kd, &x, &y, &c);
        if (1 == kd) update(x, y, c);
        else printf("%d\n", ask(x, y, c));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zzzzzzy/p/12229708.html