CDQ分治小结

本文深入探讨CDQ分治算法的应用,通过具体题目解析,如P3810三维偏序问题和CF669E Little Artem and Time Machine,阐述了如何利用CDQ分治解决复杂的数据结构和算法问题。文章详细讲解了排序、分治策略以及树状数组的使用,为读者提供了一个从理论到实践的全面理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CDQ分治小结

P3810三维偏序(陌上花开)

一道CDQ分治的比较模板又不是模板的问题.

\(f_i\)表示\(a_j<=a_i\)\(b_j<=b_i\)\(c_j<=c_i\)\(j\)的数量

对于\(d\in[0,n)\)让你求\(f(i) == d\)的数量

其实个人感觉模板的话

还是严格小于比较好做

先来考虑一下严格小于该怎么做

我们先对整体按照\(a_i\)排序,这样的话我们进行的分治就满足了第一个限制

之后我们试想一下,如果要求左区间对于右区间的贡献

我们只需要将两边分别排序

虽然这样两边就不一定在满足\(a_i\)的限制,但是左右两个区间依旧满足(因为我们是分别排序)

直接用权值树状数组计算右边对与左边的贡献

但是,如果要求小于等于,就要考虑有两个值其\(a_I,b_i,c_i\)均相同的情况

这样的话我们就去重

将重复\(n\)个的元素的权值改为\(n\)

最后

\(cnt_{ai.ans + ai.val-1}+=ai.ans\)

即可

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cctype>
#include<queue>
#include<stack>
using namespace std;
const int N = 1e5 + 3;
const int M = 2e5 + 3;
int n,k;
struct BIT{
    int c[M];
    inline int lowbit(int x){return x & -x;}
    inline void ins(int x,int v){
        for(;x <= k;x += lowbit(x)) c[x] += v;
    }
    inline int query(int x){
        int res = 0;
        for(;x;x -= lowbit(x)) res += c[x];
        return res; 
    }
}T;
struct node{
    int x,y,z;
    int val,ans;    
}a[N],b[N];
int cnt[N];
inline int read(){
    char ch = getchar();int v = 0,c = 1;
    while(!isdigit(ch)){
        if(ch == '-') c = -1;
        ch = getchar(); 
    }
    while(isdigit(ch)){
        v = v * 10 + ch - 48;
        ch = getchar(); 
    }
    return v * c;   
}
inline bool cmpx(node xx,node yy){
    if(xx.x != yy.x)
    return xx.x < yy.x;
    if(xx.y != yy.y)
    return xx.y < yy.y;
    return xx.z < yy.z;
}
inline bool cmpy(node xx,node yy){
    if(xx.y != yy.y)
    return xx.y < yy.y;
    return xx.z < yy.z;
}   
inline void solve(int l,int r){
    if(l == r) return ;
    int mid = (l + r) >> 1;
    solve(l,mid);solve(mid + 1,r);
//  printf("l:%d r:%d\n",l,r);
    sort(a + l,a + mid + 1,cmpy);
    sort(a + mid + 1,a + r + 1,cmpy);
//  for(int i = l;i <= r;++i) printf("%d %d\n",a[i].y,a[i].z);
    int top = l;
    for(int i = mid + 1;i <= r;++i){
        for(;top <= mid && a[top].y <= a[i].y;top++)
        T.ins(a[top].z,a[top].val);
    //  printf("%d %d %d\n",top,i,T.query(a[i].z));
        a[i].ans += T.query(a[i].z);
    }
    for(int i = l;i < top;++i) T.ins(a[i].z,-a[i].val);
}
int main(){
    n = read(),k = read();
    for(int i = 1;i <= n;++i)
        b[i].x = read(),b[i].y = read(),b[i].z = read();
    sort(b + 1,b + n + 1,cmpx);
    int c = 0,num = 0;
    for(int i = 1;i <= n;++i){
        c++;
        if(b[i].x != b[i + 1].x || b[i].y != b[i + 1].y || b[i].z != b[i + 1].z)
        a[++num] = b[i],a[num].val = c,c = 0;
    }
    swap(num,n);//for(int i = 1;i <= n;++i) printf("%d %d %d %d\n",a[i].x,a[i].y,a[i].z,a[i].val);
    solve(1,n);
//  for(int i = 1;i <= n;++i) printf("%d ",a[i].ans);puts("");
    for(int i = 1;i <= n;++i) cnt[a[i].ans + a[i].val - 1] += a[i].val;
    for(int i = 0;i < num;++i) printf("%d\n",cnt[i]);
    return 0;   
}

CF669E. Little Artem and Time Machine

CDQ的板子题了

我们以输入的操作顺序为第一维

操作的时间为第二维

第三维就直接查询有多少数等于他就好了

但是由于排序是将

sort(a + l,a + mid + 1,cmp)

写成了

sort(a + l + 1,a + mid + 1,cmp)

然后,调了一下午,还去找\(wqy\)学长丢人

#include<cstdio>
#include<cstring>
#include<cctype>
#include<map>
#include<algorithm>
#include<iostream>
#define LL long long
using namespace std;
const int N = 1e5 + 3;
int n;
struct Q{
    int type;
    LL time;
    LL val;
    int id;
    int ans;
}a[N];
map <LL,int> m;
inline LL read(){
    char ch = getchar();long long v = 0,c = 1;
    while(!isdigit(ch)){
        if(ch == '-') c = -1;
        ch = getchar(); 
    }
    while(isdigit(ch)){
        v = v * 10 + ch - 48;
        ch = getchar(); 
    }
    return v * c;   
}
inline bool cmp(Q x,Q y){
    return x.time < y.time; 
}
inline bool cmp2(Q x,Q y){
    return x.id < y.id;
}
inline void solve(int l,int r){
    if(l == r) return ;
    int mid = (l + r) >> 1;
    solve(l,mid);solve(mid + 1,r);
//  printf("l:%d r:%d\n",l,r);
    sort(a + l,a + mid + 1,cmp);
    sort(a + mid + 1,a + r + 1,cmp);
//  for(int i = l;i <= mid;++i) printf("%d %lld %lld\n",a[i].type,a[i].time,a[i].val);
//  printf("---------------\n");
//  for(int i = mid + 1;i <= r;++i) printf("%d %lld %lld\n",a[i].type,a[i].time,a[i].val);
    int top = l;
    for(int i = mid + 1;i <= r;++i){
        while(i <= r && a[i].type != 3) ++i;
        if(i > r) break;
        while(top <= mid && a[top].time <= a[i].time){
            if(a[top].type == 1) m[a[top].val]++;
            else if(a[top].type == 2) m[a[top].val]--;
            top++;
        }
        a[i].ans += m[a[i].val];
    }
    m.clear();
}
int main(){
    n = read();
    for(int i = 1;i <= n;++i){
        a[i].type = read();
        a[i].time = read();
        a[i].val = read();
        a[i].id = i;
    }
    solve(1,n);
    sort(a + 1,a + n + 1,cmp2); 
    for(int i = 1;i <= n;++i) if(a[i].type == 3) printf("%d\n",a[i].ans);
    return 0;   

转载于:https://www.cnblogs.com/wyxdrqc/p/10853818.html

资源下载链接为: https://pan.quark.cn/s/9648a1f24758 这个HTML文件是一个专门设计的网页,适合在告白或纪念日这样的特殊时刻送给女朋友,给她带来惊喜。它通过HTML技术,将普通文字转化为富有情感和创意的表达方式,让数字媒体也能传递深情。HTML(HyperText Markup Language)是构建网页的基础语言,通过标签描述网页结构和内容,让浏览器正确展示页面。在这个特效网页中,开发者可能使用了HTML5的新特性,比如音频、视频、Canvas画布或WebGL图形,来提升视觉效果和交互体验。 原本这个文件可能是基于ASP.NET技术构建的,其扩展名是“.aspx”。ASP.NET是微软开发的一个服务器端Web应用程序框架,支持多种编程语言(如C#或VB.NET)来编写动态网页。但为了在本地直接运行,不依赖服务器,开发者将其转换为纯静态的HTML格式,只需浏览器即可打开查看。 在使用这个HTML特效页时,建议使用Internet Explorer(IE)浏览器,因为一些老的或特定的网页特效可能只在IE上表现正常,尤其是那些依赖ActiveX控件或IE特有功能的页面。不过,由于IE逐渐被淘汰,现代网页可能不再对其进行优化,因此在其他现代浏览器上运行可能会出现问题。 压缩包内的文件“yangyisen0713-7561403-biaobai(html版本)_1598430618”是经过压缩的HTML文件,可能包含图片、CSS样式表和JavaScript脚本等资源。用户需要先解压,然后在浏览器中打开HTML文件,就能看到预设的告白或纪念日特效。 这个项目展示了HTML作为动态和互动内容载体的强大能力,也提醒我们,尽管技术在进步,但有时复古的方式(如使用IE浏览器)仍能唤起怀旧之情。在准备类似的个性化礼物时,掌握基本的HTML和网页制作技巧非常
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值