【知识】CDQ 分治!

CDQ 分治!

统计 \((a,b,c)\) 满足一定大小关系的对数。

首先排序解决掉第一维。

第二维考虑分治,对于目前要处理的区间 \([l,r]\),记 \(mid=\lfloor \frac{l+r}{2}\rfloor\)

满足条件的点对 \((p,q)\) 如果都在左区间或右区间,递归处理。

否则,考虑双指针。我们记左区间的指针为 \(j\) ,右区间的指针为 \(i\)

对于每一个 \(i\) ,我们让 \(j\) 右移,直到找到第一个 \(j\) ,满足 \(b_j>b_i\) ,那么对于 \(x\in[l,j-1]\) 均有 \(b_i\geq b_x\)

然后考虑树状数组解决第三维。

对于元素 \(x\in[l,j-1]\) ,我们把属性 \(c\) 值放入树状数组中,只需查询一下 \(query(c_i)\) 就可以找到满足 \(c_i\geq c_x\)个数了。

#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
        x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}
#define rd rd()

void wt(int x){
    if (x < 0)
        putchar('-'), x = -x;
    if (x > 9)
        wt(x / 10);
    putchar(x % 10 + '0');
    return;
}
void wt(char x){
    putchar(x);
}
void wt(int x, char k){
    wt(x),putchar(k);
}

namespace Star_F{
    const int N = 100005, M = 200005;
    int n, m;
    struct node{
        int a, b, c, s, res;
        bool operator<(const node& t) const{
            if(a!=t.a)
                return a < t.a;
            if(b!=t.b)
                return b < t.b;
            return c < t.c;
        }
        bool operator==(const node& t) const{
            return a == t.a && b == t.b && c == t.c;
        }
    } q[N], w[N];
    int tr[M], ans[N];
    int low(int x){
        return x & -x;
    }
    void add(int x,int v){
        for (int i = x; i < M;i+=low(i))
            tr[i] += v;
    }

    int query(int x){
        int res = 0;
        for (int i = x; i;i-=low(i))
            res += tr[i];
        return res;
    }

    void merge_sort(int l,int r){
        if(l>=r)
            return;
        int mid = l + r >> 1;
        merge_sort(l, mid), merge_sort(mid + 1, r);
        int i = l, j = mid + 1, k = 0;
        while (i <= mid && j <= r)
            if (q[i].b <= q[j].b) add(q[i].c, q[i].s), w[k ++ ] = q[i ++ ];
            else q[j].res += query(q[j].c), w[k ++ ] = q[j ++ ];
        while (i <= mid) add(q[i].c, q[i].s), w[k ++ ] = q[i ++ ];
        while (j <= r) q[j].res += query(q[j].c), w[k ++ ] = q[j ++ ];
        for (i = l; i <= mid; i ++ ) add(q[i].c, -q[i].s);
        for (i = l, j = 0; j < k; i ++, j ++ ) q[i] = w[j];
    }
    void Main(){
        cin >> n >> m;
        for (int i = 0; i < n;i++){
            int a, b, c;
            cin >> a >> b >> c;
            q[i] = {a, b, c, 1};
        }

        sort(q, q + n);
        int k = 1;
        for (int i = 1; i < n;i++)
            if(q[i]==q[k-1])
                q[k - 1].s++;
            else
                q[k++] = q[i];

        merge_sort(0, k - 1);
        for (int i = 0; i < k;i++)
            ans[q[i].res + q[i].s - 1] += q[i].s;
        for (int i = 0; i < n; i++)
            cout << ans[i] << endl;
    }

}

signed main(){
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    ClockA;
    int T=1;
    // T=rd;
    while(T--) Star_F::Main();
    // ClockB;
    return 0;
}

P3755 CQOI2017 老C的任务

首先明显可以差分。

把给定点的 \(id\) 设为 0,查询点的 \(id\) 设为 \(1\)

可以发现,对 \((i,j)\) 有贡献的一定要满足:

  • \(x\le i, \ \ y \ \le j, \ \ \ id<1\)

满足三位偏序,cdq 分治即可。

因为第三维只有 \(0\)\(1\),所以无需树状数组,用一个变量记录即可。

#include <bits/stdc++.h>
using namespace std;
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define ROF(i, a, b) for (int i = (a); i >= (b); --i)
#define DEBUG(x) cerr << #x << " = " << x << endl
#define ll long long
typedef pair <int, int> PII;
typedef unsigned int uint;
typedef unsigned long long ull;
#define i128 __int128
#define fi first
#define se second
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
#define ClockA clock_t start, end; start = clock()
#define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
//#define int long long
inline int rd(){
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9'){
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
        x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}
#define rd rd()

void wt(int x){
    if (x < 0)
        putchar('-'), x = -x;
    if (x > 9)
        wt(x / 10);
    putchar(x % 10 + '0');
    return;
}
void wt(char x){
    putchar(x);
}
void wt(int x, char k){
    wt(x),putchar(k);
}

namespace Star_F{
    const int N = 500005;
    int n,m;
    struct node{
        int x, y, z, p, id, sign;
        ll sum;
        bool operator<(const node& a) const{
            if(x!=a.x)
                return x < a.x;
            if(y!=a.y)
                return y < a.y;
            return z < a.z;
        }
    } q[N], w[N];
    ll ans[N];

    void merge_sort(int l,int r){
        if(l>=r)
            return;
        int mid = l + r >> 1;
        merge_sort(l, mid), merge_sort(mid + 1, r);
        int i = l, j = mid + 1, k = 0;
        ll sum = 0;
        while (i <= mid && j <= r){
            if(q[i].y<=q[j].y)
                sum += !q[i].z * q[i].p, w[k++] = q[i++];
            else
                q[j].sum += sum, w[k++] = q[j++];
        }
        while(i<=mid)
            sum += !q[i].z * q[i].p, w[k++] = q[i++];
        while(j<=r)
            q[j].sum += sum, w[k++] = q[j++];
        for (int i = l, j = 0; j < k;i++,j++)
            q[i] = w[j];
    }
    void Main(){
        cin >> n >> m;
        for (int i = 0; i < n;i++){
            int x, y, p;
            cin >> x >> y >> p;
            q[i] = {x, y, 0, p};
        }
        int k = n;
        for (int i = 1; i <= m;i++){
            int x1, y1, x2, y2;
            cin >> x1 >> y1 >> x2 >> y2;
            q[k++] = {x2, y2, 1, 0, i, 1};
            q[k++] = {x1 - 1, y2, 1, 0, i, -1};
            q[k++] = {x2, y1 - 1, 1, 0, i, -1};
            q[k++] = {x1 - 1, y1 - 1, 1, 0, i, 1};
        }
        sort(q, q + k);
        merge_sort(0, k - 1);
        for (int i = 0; i < k;i++)
            if(q[i].z)
                ans[q[i].id] += q[i].sum * q[i].sign;

        for (int i = 1; i <= m;i++)
            cout << ans[i] << endl;
    }

}

signed main(){
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    ClockA;
    int T=1;
    // T=rd;
    while(T--) Star_F::Main();
    // ClockB;
    return 0;
}

P3157 [CQOI2011] 动态逆序对

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 100010;

int n, m;
struct Data
{
    int a, t, res;
}q[N], w[N];
int tr[N], pos[N];
LL ans[N];

int lowbit(int x)
{
    return x & -x;
}

void add(int x, int v)
{
    for (int i = x; i < N; i += lowbit(i)) tr[i] += v;
}

int query(int x)
{
    int res = 0;
    for (int i = x; i; i -= lowbit(i)) res += tr[i];
    return res;
}

void merge_sort(int l, int r)
{
    if (l >= r) return;
    int mid = l + r >> 1;
    merge_sort(l, mid), merge_sort(mid + 1, r);
    int i = mid, j = r;
    while (i >= l && j > mid)
        if (q[i].a > q[j].a) add(q[i].t, 1), i -- ;
        else q[j].res += query(q[j].t - 1), j -- ;
    while (j > mid) q[j].res += query(q[j].t - 1), j -- ;
    for (int k = i + 1; k <= mid; k ++ ) add(q[k].t, -1);

    j = l, i = mid + 1;
    while (j <= mid && i <= r)
        if (q[i].a < q[j].a) add(q[i].t, 1), i ++ ;
        else q[j].res += query(q[j].t - 1), j ++ ;
    while (j <= mid) q[j].res += query(q[j].t - 1), j ++ ;
    for (int k = mid + 1; k < i; k ++ ) add(q[k].t, -1);

    i = l, j = mid + 1;
    int k = 0;
    while (i <= mid && j <= r)
        if (q[i].a <= q[j].a) w[k ++ ] = q[i ++ ];
        else w[k ++ ] = q[j ++ ];
    while (i <= mid) w[k ++ ] = q[i ++ ];
    while (j <= r) w[k ++ ] = q[j ++ ];

    for (i = l, j = 0; j < k; i ++, j ++ ) q[i] = w[j];
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i ++ )
    {
        scanf("%d", &q[i].a);
        pos[q[i].a] = i;
    }
    for (int i = 0, j = n; i < m; i ++ )
    {
        int a;
        scanf("%d", &a);
        q[pos[a]].t = j -- ;
        pos[a] = -1;
    }

    for (int i = 1, j = n - m; i <= n; i ++ )
        if (pos[i] != -1)
            q[pos[i]].t = j -- ;

    merge_sort(0, n - 1);

    for (int i = 0; i < n; i ++ ) ans[q[i].t] = q[i].res;
    for (int i = 2; i <= n; i ++ ) ans[i] += ans[i - 1];
    for (int i = 0, j = n; i < m; i ++, j -- ) printf("%lld\n", ans[j]);

    return 0;
}
posted @ 2025-03-08 16:03  Star_F  阅读(11)  评论(0)    收藏  举报