P5677 [GZOI2017] BIT

题意

传送门 P5677 [GZOI2017]配对统计

题解

A A A 中元素各不相同,那么将其排序后,对任一位置 i i i,满足条件的 j j j 只可能出现在 i − 1 , i + 1 i-1,i+1 i1,i+1,此时得到 O ( N ) O(N) O(N) 组好的配对 ( i , j ) (i,j) (i,j)

问题转化为已知多组二元组的条件下,查询某个区间包含多少个二元组。二元组 ( i , j ) (i,j) (i,j) 对查询区间 ( l , r ) (l,r) (l,r) 有贡献,仅当 l ≤ i , j ≤ r l\leq i,j\leq r li,jr。对于这类包含左右边界限制的问题,一般依次处理这样的限制。

具体而言,将查询区间离线,将二元组与查询区间按照左边界的值排序,倒着处理,那么对查询区间 ( l , r ) (l,r) (l,r) 有贡献的二元组 ( i , j ) (i,j) (i,j),满足 l ≤ i l\leq i li,且对所有未处理的查询区间都有贡献,此时即处理了左界限制。右界限制使用 B I T BIT BIT 维护即可。总时间复杂度 O ( N log ⁡ N ) O(N\log N) O(NlogN)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, l, r) for (int i = l, _ = r; i < _; ++i)
const int MAXN = 3E5 + 5;
int N, M;
struct node
{
    
    
    int a, k;
    bool operator<(const node &o) const {
    
     return a < o.a; }
} A[MAXN];
struct seg
{
    
    
    int l, r, q;
    seg() {
    
    }
    seg(int a, int b) : q(-1) {
    
     l = min(a, b), r = max(a, b); }
    bool operator<(const seg &o) const {
    
     return l < o.l; }
} P[MAXN], Q[MAXN];

int bit[MAXN];

int sum(int i)
{
    
    
    int s = 0;
    while (i)
        s += bit[i], i -= i & -i;
    return s;
}

void add(int i, int x)
{
    
    
    while (i <= N)
        bit[i] += x, i += i & -i;
}

int main()
{
    
    
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> N >> M;
    rep(i, 0, N) cin >> A[i].a, A[i].k = i;
    rep(i, 0, M) cin >> Q[i].l >> Q[i].r, --Q[i].l, --Q[i].r, Q[i].q = i;
    sort(A, A + N);
    int pn = 0;
    if (N > 1)
        P[pn++] = seg(A[0].k, A[1].k), P[pn++] = seg(A[N - 2].k, A[N - 1].k);
    rep(i, 1, N - 1)
    {
    
    
        int a = A[i].a - A[i - 1].a, b = A[i + 1].a - A[i].a;
        if (a == b)
            P[pn++] = seg(A[i].k, A[i - 1].k), P[pn++] = seg(A[i + 1].k, A[i].k);
        else
            P[pn++] = seg(A[i].k, a < b ? A[i - 1].k : A[i + 1].k);
    }
    sort(P, P + pn);
    sort(Q, Q + M);
    ll res = 0;
    for (int i = M - 1, j = pn - 1; i >= 0; --i)
    {
    
    
        while (j >= 0 && P[j].l >= Q[i].l)
            add(P[j].r + 1, 1), --j;
        res += (ll)(Q[i].q + 1) * sum(Q[i].r + 1);
    }
    cout << res << '\n';
    return 0;
}

猜你喜欢

转载自blog.csdn.net/neweryyy/article/details/121582045
BIT
今日推荐