BZOJ 5052: 繁忙的财政官

对于每一个左端点,考虑其右边那些能更新答案的点
先考虑在其右边且值比当前大的,小的可以将值翻转后做一遍
即对左端点 \(i\),找到 \(j>i\) 满足 \(a_j>a_i\)
首先找到一个 \(j\),下次在 \(j\) 右边找到一个 \(k\) 满足 \(a_j > a_k > a_i\)
但是这样的点对还是有很多,考虑找下个 \(k\) 还有一些不优的答案,所以还要满足 \(a_j-a_k>a_k-a_i\)
\(a_k<\dfrac{a_i+a_j}{2}\)
这样找到的 \(a_k\) 每次至少减半,所以对于每一个左端点 \(i\) 要找的次数就是 \(\log v\),其中 \(v\) 表示值域
而找 \(j\)\(\log n\),所以复杂度为 \(O(n\log v \log n)\)
这样找出所有点对 \((i, j)\),扫描线扫右端点处理询问
对于每个点对是一个单点取min和区间求min
假设当前处理的右端点为 \(r\),每次查询的是 \([l,r]\),相当于 \([l, n]\) 一个后缀,所以可以将位置翻转后用树状数组维护

#include <bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define pii pair<int, int>
#define lp p << 1
#define rp p << 1 | 1
#define mid ((l + r) >> 1)
#define ll long long
#define db double
#define rep(i,a,b) for(int i=a;i<b;i++)
#define per(i,a,b) for(int i=b-1;i>=a;i--)
#define Edg int ccnt=1,head[N],to[N*2],ne[N*2];void addd(int u,int v){to[++ccnt]=v;ne[ccnt]=head[u];head[u]=ccnt;}void add(int u,int v){addd(u,v);addd(v,u);}
#define Edgc int ccnt=1,head[N],to[N*2],ne[N*2],c[N*2];void addd(int u,int v,int w){to[++ccnt]=v;ne[ccnt]=head[u];c[ccnt]=w;head[u]=ccnt;}void add(int u,int v,int w){addd(u,v,w);addd(v,u,w);}
#define es(u,i,v) for(int i=head[u],v=to[i];i;i=ne[i],v=to[i])
const int MOD = 1e9 + 7;
void M(int &x) {if (x >= MOD)x -= MOD; if (x < 0)x += MOD;}
int qp(int a, int b = MOD - 2) {int ans = 1; for (; b; a = 1LL * a * a % MOD, b >>= 1)if (b & 1)ans = 1LL * ans * a % MOD; return ans % MOD;}
int gcd(int a, int b) { while (b) { a %= b; std::swap(a, b); } return a; }
char buf[1 << 21], *p1 = buf, *p2 = buf;
inline char getc() {
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
}
inline int _() {
    int x = 0, f = 1; char ch = getc();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getc(); }
    while (ch >= '0' && ch <= '9') { x = x * 10ll + ch - 48; ch = getc(); }
    return x * f;
}

const int N = 1e5 + 7;
const int INF = 0x3f3f3f3f;
int n, m, a[N], b[N], mn[N << 2], ans[N];
std::vector<std::pii> vec[N];
inline bool cmp(int x, int y) {
    return a[x] == a[y] ? x > y : a[x] > a[y];
}
void update(int p, int l, int r, int pos, int v) {
    mn[p] = std::min(mn[p], v);
    if (l == r) return;
    if (pos <= mid) update(lp, l, mid, pos, v);
    else update(rp, mid + 1, r, pos, v);
}
int query(int p, int l, int r, int pos, int v) {
    if (mn[p] > v) return 0;
    if (l == r) return l;
    if (pos <= mid) {
        int t = query(lp, l, mid, pos, v);
        if (t) return t;
    }
    return query(rp, mid + 1, r, pos, v);
}

struct QUERY {
    int l, r, id;
    bool operator < (const QUERY &p) const {
        return r < p.r;
    }
} Q[N];

void init() {
    std::sort(b + 1, b + 1 + n, cmp);
    memset(mn, 0x3f, sizeof(mn));
    rep (i, 1, n + 1) {
        int j = query(1, 1, n, b[i], INF - 1);
        while (j) {
            vec[j].pb(std::pii(b[i], a[j] - a[b[i]]));
            j = query(1, 1, n, b[i], (a[b[i]] + a[j] - 1) / 2);
        }
        update(1, 1, n, b[i], a[b[i]]);
    }
}
struct BIT {
    int tree[N];
    BIT() { memset(tree, 0x3f, sizeof(tree)); }
    inline int lowbit(int x) { return x & -x; }
    void add(int x, int v) {
        x = n - x + 1;
        for (int i = x; i <= n; i += lowbit(i))
            tree[i] = std::min(tree[i], v);
    }
    int query(int x) {
        x = n - x + 1;
        int ans = INF;
        for (int i = x; i; i -= lowbit(i))
            ans = std::min(ans, tree[i]);
        return ans;
    }
} bit;

int main() {
    n = _(), m = _();
    rep (i, 1, n + 1) a[i] = _(), b[i] = i;
    init();
    rep (i, 1, n + 1) a[i] = 1e9 - a[i] + 1;
    init();
    rep (i, 0, m) Q[i].l = _(), Q[i].r = _(), Q[i].id = i;
    std::sort(Q, Q + m);
    int cur = 1;
    rep (i, 0, m) {
        while (cur <= Q[i].r) {
            rep (j, 0, vec[cur].size()) bit.add(vec[cur][j].fi, vec[cur][j].se);
            cur++;
        }
        ans[Q[i].id] = bit.query(Q[i].l);
    }
    rep (i, 0, m) printf("%d\n", ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Mrzdtz220/p/12360854.html
今日推荐