前言

博主太菜了 学习快一年的OI了 好像没有什么会的算法
更寒碜的是 学一样还不精一样TAT
如有什么错误请各位路过的大佬指出啊感谢!

啥是CDQ啊(它的基本思想)

  • cdq 一个离线的算法
  • 我们要解决一系列问题,这些问题一般包含修改和查询操作,可以把这些问题排成一个序列,用一个区间[L,R]表示
  • 分。递归处理左边区间[L,M]和右边区间[M+1,R]的问题。
  • 治。合并两个子问题,同时考虑到[L,M]内的修改对[M+1,R]内的查询产生的影响。即,用左边的子问题帮助解决右边的子问题

分而治之就叫分治妈呀我在讲啥
这就是CDQ分治的基本思想。和普通分治不同的地方在于,普通分治在合并两个子问题的过程中,[L,M]内的问题不会对[M+1,R]内的问题产生影响。
Q: 考虑一下归并排序为什么合并的时候 只用算左边对右边区间的贡献?
因为它一个区间里的贡献已经计算完了

例题

hdu5618Jam's problem again

啊一道三维偏序魔板题

题意:给出\(n\)个点的三维坐标\((x,y,z)\) 对每个点\(i\) 找到满足\(x_j \leq x_i,y_j \leq y_i,z_j \leq z_i\)的\(j\)的数量

可以先把\(x\)这一维排序排掉 那么之后算答案的时候就不用考虑\(x\)的影响 再用类似于归并排序的算法 将\(y\)从小到大排序
那么合并左右两个区间的时候 右边区间的\(x\)必定大于左边区间的\(x\) 且在每个区间里的\(y\)都是单调递增的
那么\(y\)用two_pointer扫一下 , \(z\)用树状数组去维护

tps:

  • 每次当然不能暴力memset清空树状数组 可以考虑倒回去清空(也就是用了多少清空多少
  • 当两个点相等时 肯定只是把这个点的答案算到了一个点上 那么如何判断有没有算过呢 cdq结束之后排在\(i\)前面的点对\(i\)的贡献一定全算上了 但在\(i\)后面的点没有算上
    所以最后再计算一下漏掉的就可以了
#include<bits/stdc++.h>
#define fr(i,x,y) for(int i=x;i<=y;++i)
#define rf(i,x,y) for(int i=x;i>=y;--i)
#define LL long long
using namespace std;
const int N=1e5+10;
struct data{
    int id;
    int x,y,z;
}a[N],c[N];
int tr[N],d[N],g[N];

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

void UPD(int x,int y){
    for(;x<N;x+=lowerbit(x)) tr[x]+=y;
}

void Qk(int x){
    for(;x<N;x+=lowerbit(x)) tr[x]=0;
}

int Get(int x){
    int ans=0;
    for(;x;x-=lowerbit(x)) ans+=tr[x];
    return ans;
}

bool cmp(data xx,data yy){
    if(xx.x!=yy.x) return xx.x<yy.x;
    if(xx.y!=yy.y) return xx.y<yy.y;
    if(xx.z!=yy.z) return xx.z<yy.z;
}

bool check(data xx,data yy){
    return xx.y<=yy.y;
}

void CDQ(int l,int r){
    if(l==r) return ;
    int mid=(l+r)>>1;
    CDQ(l,mid),CDQ(mid+1,r);
    int lt=l-1,nw=l;
    fr(i,mid+1,r){
        int flg=0;
        fr(j,lt+1,mid){
            if(!check(a[j],a[i])){
                flg=1;
                lt=j-1;
                break;
            } else {
                UPD(a[j].z,1);
                c[nw++]=a[j];
            }
        }
        if(!flg) lt=mid;
        d[a[i].id]+=Get(a[i].z);
        c[nw++]=a[i];
    }
    fr(i,lt+1,mid) c[nw++]=a[i];
    fr(i,l,lt) Qk(a[i].z);
    fr(i,l,r) {
        a[i]=c[i];
    }
}

int main(){
    int T;scanf("%d",&T);
    fr(o,1,T){
        memset(d,0,sizeof d);
        int n;scanf("%d",&n);
        fr(i,1,n) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z),a[i].id=i;
        sort(a+1,a+1+n,cmp);
        CDQ(1,n);
        int lt=1;
        rf(i,n-1,1){
            if(a[i].x!=a[i+1].x||a[i].y!=a[i+1].y||a[i].z!=a[i+1].z){
                lt=1;
            } else lt++;
            d[a[i].id]+=lt-1;
        }
        fr(i,1,n) printf("%d\n",d[i]);
    }
    return 0;
}

hdu4742Pinball Game 3D

题意:给出\(n\)个点的三维坐标\((x,y,z)\) 随意排序 最长不下降的子序列长度是多少 在满足这样的条件下方案数有多少个?
并且给出的点不会重复

对每个点再维护一个\(dp\)值和方案数 大的点肯定是从小的点转移过来的 所以这里分治的顺序需要考虑一下
先递归左区间 再用左区间的值更新右区间 最后再递归右区间

#include<bits/stdc++.h>
#define fr(i,x,y) for(int i=x;i<=y;++i)
#define rf(i,x,y) for(int i=x;i>=y;--i)
#define LL long long
using namespace std;
const int N=1e5+10,mod=1073741824;
struct data{
    int x,y,z,id;
}a[N],b[N];
struct node{
    int dp;
    LL f;
}tr[N],d[N];
LL tot=0;
int Ax[N],Ay[N],Az[N];
int n,ans=0;

void read(int &x){
    char ch=getchar();x=0;
    for(;ch<'0'||ch>'9';ch=getchar());
    for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
}

void Add(LL &x,LL y){
    x=(x+y)%mod;
}

bool cmp(data xx,data yy){
    if(xx.x!=yy.x) return xx.x<yy.x;
    if(xx.y!=yy.y) return xx.y<yy.y;
    if(xx.z!=yy.z) return xx.z<yy.z;
}

bool cmpy(data xx,data yy){
    if(xx.y!=yy.y) return xx.y<yy.y;
    else return xx.z<yy.z;
}

void Go(node &x,node y){
    if(x.dp<y.dp) x.dp=y.dp,x.f=y.f;
    else if(x.dp==y.dp) Add(x.f,y.f);
}

void Ch(int x){
    if(d[x].dp<ans) return ;
    else if(d[x].dp==ans) Add(tot,d[x].f);
    else ans=d[x].dp,tot=d[x].f;
}

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

void Upd(int x,node y){
    for(;x<N;x+=lowerbit(x)) Go(tr[x],y);
}

node Get(int x){
    if(!x) return (node){0,0};
    node tmp;tmp.dp=0,tmp.f=0;
    for(;x;x-=lowerbit(x)) Go(tmp,tr[x]);
    return tmp;
}

void Qk(int x){
    for(;x<N;x+=lowerbit(x)) tr[x].dp=0,tr[x].f=0;
}

void cdq(int l,int r){
    if(l==r) return ;
    int mid=(l+r)>>1;
    cdq(l,mid);
    sort(a+l,a+1+mid,cmpy);
    sort(a+mid+1,a+1+r,cmpy);
    int pos=l-1,nw=l;
    fr(i,mid+1,r){
        while(pos+1<=mid&&a[pos+1].y<=a[i].y){
            pos++,Upd(a[pos].z,(node){d[a[pos].id].dp,d[a[pos].id].f});
        }
        node gg=Get(a[i].z);
        gg.dp++;
        Go(d[a[i].id],gg);
    }
    fr(i,l,pos) Qk(a[i].z);
    sort(a+mid+1,a+1+r,cmp);
    cdq(mid+1,r);
}

int main(){
    int T;read(T);
    fr(o,1,T){
        read(n);
        ans=0,tot=0;
        fr(i,1,n) {
            scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z),a[i].z++,a[i].id=i;
            Ax[i]=a[i].x,Ay[i]=a[i].y,Az[i]=a[i].z;
        }
        sort(Ax+1,Ax+1+n),sort(Ay+1,Ay+1+n),sort(Az+1,Az+1+n);
        Ax[0]=unique(Ax+1,Ax+1+n)-Ax-1;
        Ay[0]=unique(Ay+1,Ay+1+n)-Ay-1;
        Az[0]=unique(Az+1,Az+1+n)-Az-1;
        fr(i,1,n){
            a[i].x=lower_bound(Ax+1,Ax+1+Ax[0],a[i].x)-Ax;
            a[i].y=lower_bound(Ay+1,Ay+1+Ay[0],a[i].y)-Ay;
            a[i].z=lower_bound(Az+1,Az+1+Az[0],a[i].z)-Az;
        }
        fr(i,1,n) d[i].dp=1,d[i].f=1;
        sort(a+1,a+1+n,cmp);
        cdq(1,n);
        fr(i,1,n) Ch(i);
        printf("%d %lld\n",ans,tot);
        fr(i,1,n) d[i]=(node){0,0LL};
    }
    return 0;
}

hdu4456Crowd

给出一张\(n*n\)的坐标系 有两个操作

  1. 给\((x,y)\)的权值加上\(c\)
    2.询问与\((x,y)\)的曼哈顿距离\(\leq k\)的点的点权和
    \(n \leq 1e4,m \leq 8e4\)

坐标旋转 二维数点 CDQ

可以观察到 与一个点曼哈顿距离小于等于某个数所构成的图形是每个角都为90°的菱形

可以考虑点旋转或坐标轴旋转 避免根号 不妨将边长扩大为原来的\(\sqrt{2}\)倍
cdq时套上二维数点即可

tps: 二维数点

如果要求\((x1,y1,x2,y2)\)的价值 是不是相当于\(w_(x1,y1,0,0)-w_(x1,y2-1,0,0)-w_(x2-1,y1,0,0)+w_(x2-1,y2-1,0,0)\)
那么对于每个询问 先对时间排序 再对\(x\)排序 最后\(y\)所对应的值用树状数组去维护怎么套路和三位偏序一模一样!!

#include<bits/stdc++.h>
#define fr(i,x,y) for(int i=x;i<=y;++i)
#define rf(i,x,y) for(int i=x;i>=y;--i)
#define LL long long
using namespace std;
const int N=4e6+10,M=8e4+10,WF=3e4+10;
struct data{
    int tp,x,y,v,rk,flg;
}q[N],b[N];
int ans[M],tr[N];
int n,m;

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

void Upd(int x,int y){
    for(;x<N;x+=lowerbit(x)) tr[x]+=y;
}

int Get(int x){
    int ans=0;
    for(;x;x-=lowerbit(x)) ans+=tr[x];
    return ans;
}

void cdq(int l,int r){
    if(l==r) return ;
    int mid=(l+r)>>1;
    cdq(l,mid),cdq(mid+1,r);
    int pos=l-1,nw=l;
    //printf("l=%d r=%d\n",l,r);
    fr(i,mid+1,r){
        while(pos+1<=mid&&q[pos+1].x<=q[i].x){
            pos++;b[nw++]=q[pos];
            if(q[pos].tp==1) {
      //          cout<<q[pos].y<<" zz"<<q[pos].v<<endl;
                Upd(q[pos].y,q[pos].v);
            }
        }
        if(q[i].tp==2) {
            ans[q[i].rk]+=q[i].flg*Get(q[i].y);
      //      cout<<q[i].rk<<" ??"<<ans[q[i].rk]<<endl;
        }
        b[nw++]=q[i];
    }
    fr(i,pos+1,mid) b[nw++]=q[i];
    fr(i,l,pos) if(q[i].tp==1) Upd(q[i].y,-q[i].v);
    fr(i,l,r) {
        q[i]=b[i];
       // printf("tp=%d x=%d y=%d v=%d flg=%d rk=%d\n",q[i].tp,q[i].x,q[i].y,q[i].v,q[i].flg,q[i].rk);
    }
}

int main(){
    while(scanf("%d",&n)==1&&n){
        scanf("%d",&m);
        int cnt=0,tot=0;
        fr(i,1,m){
            int tp,x,y,v;
            scanf("%d%d%d%d",&tp,&x,&y,&v);
            if(tp==1) q[++tot].tp=tp,q[tot].x=x+y+WF,q[tot].y=x-y+WF,q[tot].v=v;
            else {
                int nx=x+y+WF,ny=x-y+WF;++cnt;
                q[++tot].tp=tp,q[tot].x=nx-v-1,q[tot].y=ny+v,q[tot].rk=cnt,q[tot].flg=-1;
                q[++tot].tp=tp,q[tot].x=nx+v,q[tot].y=ny-v-1,q[tot].rk=cnt,q[tot].flg=-1;
                q[++tot].tp=tp,q[tot].x=nx+v,q[tot].y=ny+v,q[tot].rk=cnt,q[tot].flg=1;
                q[++tot].tp=tp,q[tot].x=nx-v-1,q[tot].y=ny-v-1,q[tot].rk=cnt,q[tot].flg=1;
            }
        }
       /* fr(i,1,tot){
            printf("tp=%d x=%d y=%d v=%d flg=%d rk=%d\n",q[i].tp,q[i].x,q[i].y,q[i].v,q[i].flg,q[i].rk);
        }*/
        cdq(1,tot);
        //TAT
        fr(i,1,cnt) printf("%d\n",ans[i]);
        fr(i,1,cnt) ans[i]=0;
      //  puts("WTF!\n");
    }
    return 0;
}

CQOI2011动态逆序对 1A真是开心~

本题是删除一个数之后 求出所有逆序对的数量
发现正着做好像很难啊啊w(゚Д゚)w
"遇难则反"
所以倒过来 我们考虑插入
那么是不是是需要考虑每次插入一个数 所增加的逆序对数是多少?
这样我们就很容易转换成了三位偏序问题
第一维是时间 第二维是位置 第三维是值
套个魔板就珂以啦QwQ

#include<bits/stdc++.h>
#define fr(i,x,y) for(int i=x;i<=y;++i)
#define rf(i,x,y) for(int i=x;i>=y;--i)
#define LL long long
using namespace std;
const int N=1e5+10;
struct data{
    int x,y,z;
}qx[N],gg[N];
int n,m;
int ys[N],vis[N],a[N];
LL tr[N],ans[N];

void read(int &x){
    char ch=getchar();x=0;
    for(;ch<'0'||ch>'9';ch=getchar()) ;
    for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
}

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

LL Get(int x){
    LL ans=0;
    if(!x) return 0LL;
    for(;x;x-=lowerbit(x)) ans+=tr[x];
    return ans;
}

void Upd(int x,int k){
    for(;x<N;x+=lowerbit(x)) tr[x]+=k;
}

void Qk(int x){
    for(;x<N;x+=lowerbit(x)) tr[x]=0;
}

void cdq(int l,int r){
    int mid=(l+r)>>1;
    if(l==r) return ;
    cdq(l,mid),cdq(mid+1,r);
    int pos=l-1,nw=l;
    //printf("l=%d r=%d\n",l,r);
    fr(i,mid+1,r){
        while(pos+1<=mid&&qx[pos+1].y<qx[i].y){
            pos++,gg[nw++]=qx[pos],Upd(qx[pos].z,1);
        }
        gg[nw++]=qx[i];
        ans[qx[i].x]+=(pos-l+1)-Get(qx[i].z-1);
    }
    fr(i,pos+1,mid) gg[nw++]=qx[i];
    fr(i,l,pos) Qk(qx[i].z);
    pos=mid+1;
    rf(i,r,mid+1){
        while(pos-1>=l&&qx[pos-1].y>qx[i].y){
            pos--,Upd(qx[pos].z,1);
        }
        ans[qx[i].x]+=Get(qx[i].z-1);
    }
    fr(i,pos,mid) Qk(qx[i].z);
    fr(i,l,r) qx[i]=gg[i];
}

int main(){
    read(n),read(m);
    fr(i,1,n) scanf("%d",&a[i]),ys[a[i]]=i;
    int cz=n+1;
    fr(i,1,m){
        int x;scanf("%d",&x);
        vis[x]=1;
        qx[--cz].y=ys[x],qx[cz].z=x,qx[cz].x=cz;
    }
    fr(i,1,n) if(!vis[i]) qx[--cz].y=ys[i],qx[cz].z=i,qx[cz].x=cz;
    cdq(1,n);
    /*fr(i,1,n){
        printf("mdans=%lld\n",ans[i]);
    }*/
    fr(i,1,n) ans[i]+=ans[i-1];
    rf(i,n,n-m+1) printf("%lld\n",ans[i]);
    return 0;
}

bzoj1492|NOI2007货币兑换

题意 还是看原题吧TAT

可以显然得出 每一天要么不操作要么全部卖出 要不全部买入
那么我们设\(dp[i]\)表示前\(i\)天的最大获利
\[dp[i]=dp[i-1]\]
\[dp[i]=max_{j=1}^{i-1}(\dfrac{dp[j]*R[j]}{R[j]*A[j]+B[j]}*A[i]+\dfrac{f[j]}{R[j]*A[j]+B[j]}*B[i])\]
我们把\(\dfrac{dp[j]*R[j]}{R[j]*A[j]+B[j]}\)记作\(x\) , \(\dfrac{f[j]}{R[j]*A[j]+B[j]}\)记作\(y\)
\[dp[i]=max_{j=1}^{i-1}(x*A[i]+y*B[i])\]
是不是可以斜率优化啊QwQ 但是这个斜率并不是单调的QwQ
这里介绍cdq分治 我不会splay啊TAT
左区间将\(x,y\)水平序排序 维护一个斜率递减的凸包
右区间将斜率\(\frac{-A[i]}{B[i]}\)排序
就可以啦
注意一下细节

#include<bits/stdc++.h>
#define fr(i,x,y) for(int i=(x);i<=(y);++i)
#define rf(i,x,y) for(int i=(x);i>=(y);--i)
#define LL long long
#define db double
using namespace std;
const int N=1e5+10;
const db eps=1e-10;
struct data{
    int id;
    db x,y,A,B,R,k;
}q[N];
int Q[N];
db dp[N];

bool comp(data xx,data yy){
    return xx.k<yy.k;
}

bool cmp(data xx,data yy){
    return xx.x<yy.x||(xx.x==yy.x&&xx.y<yy.y);
}

bool Cmp(data xx,data yy){
    return xx.id<yy.id;
}

db Cross(db xx,db xy,db yx,db yy){
    return xx*yy-xy*yx;
}

db js(int tp,int i){
    return q[Q[tp]].x*q[i].A+q[Q[tp]].y*q[i].B;
}

void cdq(int l,int r){
    if(l==r){
       // cout<<q[l].id<<"WAI"<<endl;
        dp[q[l].id]=max(dp[q[l].id],dp[q[l].id-1]);
        q[l].x=dp[q[l].id]/(q[l].R*q[l].A+q[l].B)*q[l].R;
        q[l].y=dp[q[l].id]/(q[l].R*q[l].A+q[l].B);
        return ;
    }
    int mid=(l+r)>>1;
    cdq(l,mid);
    sort(q+l,q+mid+1,cmp);
    sort(q+mid+1,q+r+1,comp);
    int tp=0;
    /*fr(i,mid+1,r){
        db maxn=0;int kk=-1;
        fr(j,l,mid) {
            if(maxn<q[j].x*q[i].A+q[j].y*q[i].B) kk=j;
            maxn=max(maxn,q[j].x*q[i].A+q[j].y*q[i].B);
        }
        dp[q[i].id]=max(dp[q[i].id],maxn);
        printf("gg%d %lf %d\n",q[i].id,dp[q[i].id],kk);
    }*/
    fr(i,l,mid){
        while(tp>=2&&Cross(q[i].x-q[Q[tp]].x,q[i].y-q[Q[tp]].y,q[i].x-q[Q[tp-1]].x,q[i].y-q[Q[tp-1]].y)<=0) tp--;
        Q[++tp]=i;
    }
    fr(i,mid+1,r){
        db pos=js(tp,i);
        while(js(tp-1,i)>pos) tp--,pos=js(tp,i);
        dp[q[i].id]=max(dp[q[i].id],pos);
    }
    sort(q+mid+1,q+r+1,Cmp);
    cdq(mid+1,r);
}

int main(){
    int n;
    scanf("%d%lf",&n,&dp[0]);
    fr(i,1,n){
        q[i].id=i;
        scanf("%lf%lf%lf",&q[i].A,&q[i].B,&q[i].R);
        q[i].k=-q[i].A/q[i].B;
    }
    cdq(1,n);
  //  fr(i,0,n) printf("%.3f\n",dp[i]);
    printf("%.3f\n",dp[n]);
    return 0;
}

/*
10 100
5.007 5.139 1.44
5.142 5.963 1.39
5.248 5.038 1.06
5.705 5.606 1.07
5.151 5.067 1.86
5.924 5.979 1.88
5.069 5.912 1.28
5.075 5.092 1.77
5.485 5.409 1.28
5.161 5.233 1.63
148.311
*/

bzoj4553序列

题意 给出一个数组\(a[]\)
有\(m\)个操作 每次操作修改\(a_x\)为\(y\) 操作之间不影响
问这个数组的最长子序列使得在每一次操作过后都是非递减的QwQ

由于每一次操作都只修改一个位置 所以 每个位置在所有操作中的最大\(mx_i\)和最小值\(mn_i\)我们都可以知道
对于\(i < j\) 若\(j\)能够接到\(i\)的后面
那么必须满足 \(mx[i] \leq a[j]\) && \(a[i] \leq mn[j]\)
对左区间按\(a\)排序 右区间按照\(mn\)排序
\(mx_j\)和\(a_i\)的关系用树状数组维护

#include<bits/stdc++.h>
#define fr(i,x,y) for(int i=x;i<=y;++i)
#define rf(i,x,y) for(int i=x;i>=y;--i)
#define LL long long
using namespace std;
const int N=1e5+10;
int ans=0;
int b[N],dp[N],mx[N],mn[N],a[N],tr[N];

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

void Upd(int x,int y){
    for(;x<N;x+=lowerbit(x)) tr[x]=max(tr[x],y);
}

void Qk(int x){
    for(;x<N;x+=lowerbit(x)) tr[x]=0;
}

int Get(int x){
    int pos=0;
    for(;x;x-=lowerbit(x)) pos=max(pos,tr[x]);
    return pos;
}

bool cmp1(int x,int y){
    return a[x]<a[y];
}

bool cmp2(int x,int y){
    return mn[x]<mn[y];
}

bool cmp3(int x,int y){
    return x<y;
}

void cdq(int l,int r){
    if(l==r) return ;
    int mid=(l+r)>>1;
    cdq(l,mid);
    sort(b+l,b+mid+1,cmp1);
    sort(b+mid+1,b+r+1,cmp2);
    int pos=l-1;
    fr(i,mid+1,r){
        while(pos+1<=mid&&a[b[pos+1]]<=mn[b[i]]){
            pos++;
            Upd(mx[b[pos]],dp[b[pos]]);
        }
        dp[b[i]]=max(dp[b[i]],Get(a[b[i]])+1);
    }
    fr(i,l,pos) Qk(mx[b[i]]);
    sort(b+mid+1,b+r+1,cmp3);
    cdq(mid+1,r);
}

int main(){
    int n,m;scanf("%d%d",&n,&m);
    fr(i,1,n) scanf("%d",&a[i]),mx[i]=a[i],mn[i]=a[i];
    fr(i,1,m){
        int x,y;
        scanf("%d%d",&x,&y);
        mx[x]=max(mx[x],y);
        mn[x]=min(mn[x],y);
    }
    fr(i,1,n) b[i]=i,dp[i]=1;
    cdq(1,n);
    fr(i,1,n) ans=max(ans,dp[i]);
    printf("%d\n",ans);
    return 0;
}

后记

啊...cdq就学习到这里吧
根据517的指示 魔版题也差不多做了做
剩下的就随缘了

参考博文

__stdcall 【教程】简易CDQ分治教程&学习笔记

学习笔记 | CDQ分治的更多相关文章

  1. [学习笔记] CDQ分治 从感性理解到彻底晕菜

    最近学了一种叫做CDQ分治的东西...用于离线处理一系列操作与查询似乎跑得很快233 CDQ的名称似乎源于金牌选手陈丹琦 概述: 对于一坨操作和询问,分成两半,单独处理左半边和处理左半边对于右半边的影 ...

  2. [学习笔记]CDQ分治和整体二分

    序言 \(CDQ\) 分治和整体二分都是基于分治的思想,把复杂的问题拆分成许多可以简单求的解子问题.但是这两种算法必须离线处理,不能解决一些强制在线的题目.不过如果题目允许离线的话,这两种算法能把在线 ...

  3. [学习笔记] CDQ分治&整体二分

    突然诈尸.png 这两个东西好像都是离线骗分大法... 不过其实这两个东西并不是一样的... 虽然代码长得比较像 CDQ分治 基本思想 其实CDQ分治的基本思想挺简单的... 大概思路就是长这样的: ...

  4. 学习笔记——CDQ分治

    再次感谢这位大佬的博客:https://www.cnblogs.com/ljc20020730/p/10395866.html CDQ分治,是一种在分治合并中计算前面值对后面答案的贡献的一种算法.今天 ...

  5. 算法笔记--CDQ分治 && 整体二分

    参考:https://www.luogu.org/blog/Owencodeisking/post-xue-xi-bi-ji-cdq-fen-zhi-hu-zheng-ti-er-fen 前置技能:树 ...

  6. 一篇自己都看不懂的CDQ分治&整体二分学习笔记

    作为一个永不咕咕咕的博主,我来更笔记辣qaq CDQ分治 CDQ分治的思想还是比较简单的.它的基本流程是: \(1.\)将所有修改操作和查询操作按照时间顺序并在一起,形成一段序列.显然,会影响查询操作 ...

  7. 【教程】简易CDQ分治教程&学习笔记

    前言 辣鸡蒟蒻__stdcall终于会CDQ分治啦!       CDQ分治是我们处理各类问题的重要武器.它的优势在于可以顶替复杂的高级数据结构,而且常数比较小:缺点在于必须离线操作. CDQ分治的基 ...

  8. [偏序关系与CDQ分治]【学习笔记】

    组合数学真是太棒了 $CDQ$真是太棒了(雾 参考资料: 1.<组合数学> 2.论文 课件 很容易查到 3.sro __stdcall 偏序关系 关系: 集合$X$上的关系是$X$与$X$ ...

  9. 初学cdq分治学习笔记(可能有第二次的学习笔记)

    前言骚话 本人蒟蒻,一开始看到模板题就非常的懵逼,链接,学到后面就越来越清楚了. 吐槽,cdq,超短裙分治....(尴尬) 正片开始 思想 和普通的分治,还是分而治之,但是有一点不一样的是一般的分治在 ...

随机推荐

  1. Servlet 核心接口

    在Servlet体系结构中,除了用于实现Servlet的Servlet接口.GenericServlet类和HttpServlet类外,还有一些辅助Servlet获取相关资源信息的重要接口,了解这些接 ...

  2. Jenkins 在mac平台的安装与配置

    1. 安装: 强烈推荐直接下载war包方式安装,方便修改项目工作目录.首先确保电脑上安装了java,接着下载tomcat(任意版本).将tomcat安装在任意想要的目录,然后下载jenkins war ...

  3. 抓取js动态生成的数据分析案例

    需求:爬取https://www.xuexi.cn/f997e76a890b0e5a053c57b19f468436/018d244441062d8916dd472a4c6a0a0b.html页面中的 ...

  4. Postman-断言和Runner

    断言(部分) // 推荐用全等 ===,确保类型和值都一致 tests['Status code is 200'] = responseCode.code === 200; //判断响应结果是否是20 ...

  5. OpenCV——直方图均衡化(用于图像增强)

    #include <opencv2/opencv.hpp> #include <iostream> #include <math.h> using namespac ...

  6. docker pull下载镜像时的报错及其解决方法

    使用docker pull从镜像仓库拉取镜像时报错如下: [root@docker-registry ~]# docker pull centos Using default tag: latest ...

  7. javascript瀑布流效果

    javascript瀑布流效果 其实javascript瀑布流 前几年都已经很流行了(特别是美丽说,蘑菇街),最近看到网上有人问这个瀑布流效果,所以自己有空的时候就研究了下,其实也是研究别人的代码,研 ...

  8. JS编写简单的弹窗插件(含有demo和源码)

    最近项目做完了 事情不是很多,今天正好也在调休,所以趁着这个时间研究了一下简易的JS弹窗功能,当然网上这块插件非常多,本人也没有仔细看网上的插件源码 只是凭着日常使用过的弹窗插件有这么多功能 来实现自 ...

  9. PAT B1008 数组元素循环右移问题 (20 分)

    一个数组A中存有N(>)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(≥)个位置,即将A中的数据由(A​0​​A​1​​⋯A​N−1​​)变换为(A​N−M​​⋯A​N−1​​A ...

  10. mybatis的一对一,一对多查询,延迟加载,缓存介绍

    一对一查询 需求 查询订单信息关联查询用户信息 sql语句 /*通过orders关联查询用户使用user_id一个外键,只能关联查询出一条用户记录就可以使用内连接*/ SELECT orders.*, ...