CDQ 分治算法模板

Posted Guess2

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CDQ 分治算法模板相关的知识,希望对你有一定的参考价值。

CDQ分治

1.三维偏序问题:三维偏序(陌上花开)

#include<bits/stdc++.h>
#define RG register
#define IL inline
#define _ 200005
using namespace std;
IL int gi(){
    RG int data = 0 , m = 1; RG char ch = 0;
    while(ch != '-' && (ch<'0'||ch>'9'))ch = getchar();
    if(ch == '-'){m = -1; ch = getchar();}
    while('0'<=ch && ch<='9')
        data = (data<<3) + (data<<1) + (ch - '0') , ch = getchar();
    return (m) ? data : -data;
}

int tot,bt[_],n,k,f[_],g[_],blg[_]; long long ans[_];

struct Node{
    int a, b, c , w , id;
    //w记录这个节点对应多少个真实节点,id则是其对应编号.
    bool operator <(const Node &B)const{
         return (b == B.b) ? c <= B.c : b < B.b;}
};
Node q1[_],q[_],tmp[_];

namespace BIT{
    IL void Update(RG int ps,RG int dt){
       for(RG int i = ps; i <= k; i += (i&-i))bt[i] += dt;
    }
    IL void Clear(RG int ps){
       for(RG int i = ps; i <= k; i += (i&-i))bt[i] = 0;
    }
    IL int Query(RG int ps){
        RG int res = 0;
        for(RG int i = ps; i > 0; i -= (i&-i))res += bt[i];
        return res;
    }
}

void cdq(RG int L,RG int R){
    if(L == R)return;
    RG int mid = (L+R)>>1; cdq(L,mid); cdq(mid+1,R);
    RG int l = L , r = mid+1 , oo = L-1;
    while(l <= mid && r <= R){
        if(q[l] < q[r])
            BIT::Update(q[l].c,q[l].w) ,
            tmp[++oo] = q[l++];
        else
            g[q[r].id] += BIT::Query(q[r].c) ,
            tmp[++oo] = q[r++];
    }
    while(l <= mid)tmp[++oo] = q[l++];
    while(r <= R)
        g[q[r].id] += BIT::Query(q[r].c) ,
        tmp[++oo] = q[r++];
    for(RG int i = L; i <= R; i ++)
        BIT::Clear(tmp[i].c) , q[i] = tmp[i];
    return;
}

IL bool cmp(Node a,Node b){
    if(a.a != b.a)return a.a < b.a;
    if(a.b != b.b)return a.b < b.b;
    if(a.c != b.c)return a.c < b.c;
    return a.id < b.id;   //注意:这里一定要随便定义一个优先级
}
IL bool Equl(int nw,int cp){
    if(!cp)return false;
    else  return (q1[nw].a==q[cp].a &&
          q1[nw].b==q[cp].b && q1[nw].c==q[cp].c);
}

int main(){
    n = gi(); k = gi();
    for(RG int i = 1,a,b,c; i <= n; i ++)
        a = gi(),b = gi(),c = gi(),
        q1[i] = (Node){a , b , c , 1 , i};
    
    //去重:
    tot = 0;
    sort(q1+1,q1+n+1,cmp);
    for(RG int i = 1; i <= n; i ++){
        if(!Equl(i,tot))
            q[++tot] = q1[i] , q[tot].w = 1 , q[tot].id = tot;
        else q[tot].w ++;
        blg[i] = tot;          //记录i点是对应去重后的哪个节点
    }

    cdq(1,tot);
    // f[i] 表示去重前点i满足 (aj<=ai,bj<=bi,cj<=ci) 的j的个数.
    // g[i] 表示去重后点i满足条件的j的个数
    for(RG int i = 1; i <= tot; i ++)g[q[i].id] += q[i].w-1;
    for(RG int i = 1; i <= n; i ++)f[i] = g[blg[i]];
    for(RG int i = 1; i <= n; i ++)ans[f[i]] ++;
    for(RG int i = 0; i < n; i ++)printf("%lld\n",ans[i]);
    return 0;
}

2.动态逆序对问题:[CQOI2011]动态逆序对

#include<bits/stdc++.h>
#define RG register
#define IL inline
#define _ 300005
using namespace std;

IL int gi(){
    RG int data = 0 , m = 1; RG char ch = 0;
    while(ch != '-' && (ch<'0'||ch>'9'))ch = getchar();
    if(ch == '-'){m = -1; ch = getchar();}
    while('0'<=ch && ch<='9')
        data = (data<<3) + (data<<1) + (ch - '0') , ch = getchar();
    return (m) ? data : -data;
}

struct Query{
  int tm , ps , val;
  bool operator < (const Query &B)const{ return ps < B.ps; }
};
Query q[_] , tmp[_];
int ans[_],bt[_],n,m,pos[_]; long long Ans; bool vis[_];

namespace BIT{
    IL void Update(RG int ps,RG int dt){
       for(RG int i = ps; i <= n; i += (i&-i))bt[i] += dt;
    }
    IL int Query(RG int ps){
        RG int res = 0;
        for(RG int i = ps; i > 0; i -= (i&-i))res += bt[i];
        return res;
    }
}

void cdq(RG int L,RG int R){
    if(L == R)return;
    RG int mid = (L+R)>>1; cdq(L,mid);  cdq(mid+1,R);
    RG int l = L , r = mid+1 , oo = L-1;
    while(l<=mid && r<=R)
        if(q[l] < q[r])tmp[++oo] = q[l++];  else tmp[++oo] = q[r++];
    while(l<=mid)tmp[++oo] = q[l++];
    while(r<=R)tmp[++oo] = q[r++];
    for(RG int i = L; i <= R; i ++)q[i] = tmp[i];

    //get - behind - smaller
    for(RG int i = L; i <= R; i ++)
        if(q[i].tm <= mid)BIT::Update(q[i].val,1);
        else ans[q[i].tm] += BIT::Query(n) - BIT::Query(q[i].val);         
    for(RG int i = L; i <= R; i ++)
        if(q[i].tm <= mid)BIT::Update(q[i].val,-1);

    //get - front - bigger
    for(RG int i = R; i >= L; i --)
        if(q[i].tm <= mid)BIT::Update(q[i].val,1);
        else ans[q[i].tm] += BIT::Query(q[i].val);
    for(RG int i = R; i >= L; i --)
        if(q[i].tm <= mid)BIT::Update(q[i].val,-1);

    return;
}

IL bool cmp(Query a,Query b){return a.tm<b.tm;}

int main(){
    n = gi(); m = gi();
    RG int tot = 0;
    for(RG int u,i = 1; i <= n; i ++)
        u = gi() , pos[u] = i , vis[u] = 1;
    for(RG int u,i = n; i >= n-m+1; i --)
        u = gi() , vis[u] = 0 ,
        q[++tot] = (Query){i,pos[u],u};
    RG int cnt = n - m + 1;
    for(RG int i = 1; i <= n; i ++)
        if(vis[i])q[++tot] = (Query){--cnt,pos[i],i};
    sort(q+1,q+tot+1,cmp);
    cdq(1,tot);
    Ans = 0;
    for(RG int i = 1; i <= n; i ++)Ans += ans[i];
    for(RG int i = n; i >= n-m+1; i --)
        printf("%lld\n",Ans) , Ans -= ans[i];
    return 0;
}

离线修改与查询问题:树状数组 1

#include<bits/stdc++.h>
#define RG register
#define IL inline
#define ll long long
#define _ 4*500005
using namespace std;

int n,m,ask,tot; ll ans[_];

struct Do{
    int typ,pos,val;
    bool operator <(const Do &B)const{
    return (pos == B.pos)?typ < B.typ : pos < B.pos; }
};
Do q[_],tmp[_];

void cdq(RG int L,RG int R){
    if(L == R)return;
    RG int mid = (L+R)>>1; cdq(L,mid); cdq(mid+1,R);
    RG ll upt = 0 , l = L , r = mid+1 , oo = 0;
    while(l <= mid && r <= R){
        if(q[l] < q[r]){
            if(q[l].typ == 1)upt += q[l].val;
            tmp[++oo] = q[l++];
        }
        else {
            if(q[r].typ == 2)ans[q[r].val] -= upt;
            if(q[r].typ == 3)ans[q[r].val] += upt;
            tmp[++oo] = q[r++];
        }
    }
    while(l <= mid){
        if(q[l].typ == 1)upt += q[l].val;
        tmp[++oo] = q[l++];
    }
    while(r <= R){
        if(q[r].typ == 2)ans[q[r].val] -= upt;
        if(q[r].typ == 3)ans[q[r].val] += upt;
        tmp[++oo] = q[r++];
    }
    for(RG int i = L; i <= R; i ++)q[i] = tmp[i-L+1];
}

int main(){
    scanf("%d %d",&n,&m);
    for(RG int i = 1,ww; i <= n; i ++)
        scanf("%d",&ww), q[++tot] = (Do){1,i,ww};
    ask = 0;
    for(RG int i = 1,tp,ps,ww; i <= m; i ++){
        scanf("%d %d %d",&tp,&ps,&ww);
        if(tp == 1)q[++tot] = (Do){1,ps,ww};
        else
            q[++tot] = (Do){2,ps-1,++ask} ,
            q[++tot] = (Do){3,ww,ask};
    }
    cdq(1,tot);
    for(RG int i = 1; i <= ask; i ++)cout<<ans[i]<<endl;
    return 0;
}

以上是关于CDQ 分治算法模板的主要内容,如果未能解决你的问题,请参考以下文章

算法CDQ分治初探

P3810 模板三维偏序(陌上花开)(cdq分治)

模板CDQ分治

CDQ分治模板题

洛谷.3374.[模板]树状数组1(CDQ分治)

CDQ分治嵌套模板:多维偏序问题