前言

博主太菜了 学习快一年的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. StringBuffer&StringBuilder类

    0. 说明 1. 总体说明 当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类. 和 String 类不同的是,StringBuffer 和 String ...

  2. vc获取当前进程CPU使用率

    double GetCPUUserRate() { HANDLE hProcess=::GetCurrentProcess(); static DWORD s_dwTickCountOld = 0; ...

  3. Redis-安装时问题整理

    一.Redis编译: 1.问题:make gcc error yum –y install gcc 2.问题:安装报错 error: jemalloc/jemalloc.h: No such file ...

  4. Django商城项目笔记No.13用户部分-用户中心个人信息

    首先处理个人信息的显示 邮箱绑定: 首先给用户的模型类里添加一个字段来说明用户的邮箱是否激活 然后数据库迁移 python manage.py makemigrations python manage ...

  5. NOIP模拟赛-2018.11.6

    NOIP模拟赛 今天想着反正高一高二都要考试,那么干脆跟着高二考吧,因为高二的比赛更有技术含量(我自己带的键盘放在这里). 今天考了一套英文题?发现阅读理解还是有一些困难的. T1:有$n$个点,$m ...

  6. php 数据集转换树、递归重组节点信息多维数组(转)

    一.将数据集转换成树 /** * 将返回的数据集转换成树 * @param array $list 数据集 * @param string $pk 主键 * @param string $pid 父节 ...

  7. linux 设置默认网关永久

    .永久添加 1 2 vim /etc/sysconfig/network GATEWAY=192.168.1.4

  8. P2384 最短路

    题目背景 狗哥做烂了最短路,突然机智的考了Bosh一道,没想到把Bosh考住了...你能帮Bosh解决吗? 他会给你100000000000000000000000000000000000%10金币w ...

  9. scp 免密登录ssh-copy-id 如何使用非22端口 + rsync 同步远程机器的文件到本地

    其中:id_rsa为私钥文件,id_rsa.pub为公钥文件 ssh-copy-id  -i ~/.ssh/id_rsa.pub  "-p 2122  root@IP " 我的:s ...

  10. ORA-02291: 违反完整约束条件 - 未找到父项关键字

    由于大意,在设置数据库表时将外键字段的类型与外键表的主键字段类型不一致,造成此错误. 我的情况是: 1.将一个为number(10)的外键设置成了number(19) 2.将外键字段对应的主键表设置成 ...