今天写了到偏序问题,发现博主真的是个傻X

传送门

以前的写法

/**************************************************************
    Problem: 3262
    User: MiEcoku
    Language: C++
    Result: Accepted
    Time:3416 ms
    Memory:6296 kb
****************************************************************/

#include <cstdio>
#include <algorithm>
using namespace std;
#define mid ( l + r >> 1)
#define lowbit(x) ( x & -x)

struct GG {
    int x, y, z, id, w;
    void get () {
        scanf("%d%d%d", &x, &y, &z);
    }
}a[], b[];

], k;
; ; x -= lowbit(x)) ans += dis[x]; return ans; }
void add(int x, int y) { for ( ; x <= k; x += lowbit(x)) dis[x] += y; }

bool cmp1(GG a, GG b) { return a.x < b.x || (a.x == b.x && a.y < b.y) || (a.x == b.x && a.y == b.y && a.z < b.z); }
bool cmp2(GG a, GG b) { return a.y < b.y || (a.y == b.y && a.z < b.z); }

];
void cdq(int l, int r) {
    , r);
    sort(b+l, b+mid+, cmp2); sort(b+mid+, b+r+, cmp2);
    ;
    for ( int i = l; i <= mid; i ++) {
        while( b[q].y < b[i].y && q <= r) ans[b[q].id] += query(b[q].z), q ++;
        add(b[i].z, b[i].w);
    }
    while( q <= r) ans[b[q].id] += query(b[q].z), q ++;
    for ( int i = l; i <= mid; i ++) add(b[i].z, -b[i].w);
}

];
int main() {
    scanf("%d%d", &_, &k);
    ; i <= _; i ++) a[i].get();
    sort( a+, a++_, cmp1);
    ; i <= _; i ++) {
        cnt ++;
        ].x || a[i].y != a[i+].y || a[i].z != a[i+].z)
        b[++ n] = a[i], b[n].w = cnt, cnt = , b[n].id = n;
    }
    cdq(, n);
    ; i <= n; i ++)
        d[ans[b[i].id]+b[i].w-] += b[i].w;
    ; i < _; i ++) printf("%d\n", d[i]);
}

可以看出这是个n * logn^2 的算法,这也是博主在大多数地方看到的写法,结果傻叉的以为cdq就是n * long n ^ 2 的算法

实际上可不可以更快?

void cdq(int l, int r) {
    , r);
    sort(b+l, b+mid+, cmp2); sort(b+mid+, b+r+, cmp2);
    ;
    for ( int i = l; i <= mid; i ++) {
        while( b[q].y < b[i].y && q <= r) ans[b[q].id] += query(b[q].z), q ++;
        add(b[i].z, b[i].w);
    }
    while( q <= r) ans[b[q].id] += query(b[q].z), q ++;
    for ( int i = l; i <= mid; i ++) add(b[i].z, -b[i].w);
}

可以看出,在cdq内部排了个序,然而真的有这个必要吗? 答案是否定的

我们都知道归并排序,可以看出,内部这个排序无非是想要将第二位排序

但在内部这个循环内就已经排序,所以那个排序可以省略

我们新开个数组

void cdq(int l, int r) {
    , r);
    , cnt = ;
    for ( int i = l; i <= mid; i ++) {
        while( b[q].y < b[i].y && q <= r) ans[b[q].id] += query(b[q].z), T[++ cnt] = b[q], q ++;
        add(b[i].z, b[i].w); T[++ cnt] = b[i];
    }
    while( q <= r) ans[b[q].id] += query(b[q].z), T[++ cnt] = b[q], q ++;
    for ( int i = l; i <= mid; i ++) add(b[i].z, -b[i].w);
    cnt = ;
    for ( int i = l; i <= r; ++ i) b[i] = T[++ cnt];
}

这样,我们就省略了内部的一个排序问题,做到n * long n

还能再快不?

能!

    for ( int i = l; i <= mid; i ++) add(b[i].z, -b[i].w);

对于这句话,我们能不能将它优化掉?

我们考虑加入一个时间戳 tim

int query(int x, int K) {
    ;
    ; x -= lowbit(x)) if( mark[x] == K) ans += dis[x];
    return ans;
}
void add(int x, int y, int K) {
    for ( ; x <= k; x += lowbit(x)) if( mark[x] == K) dis[x] += y;
    else mark[x] = K, dis[x] = y;
}

然后对树状数组进行点修改

这样我们就将常数再次优化了下

上总代码

/**************************************************************
    Problem: 3262
    User: MiEcoku
    Language: C++
    Result: Accepted
    Time:1428 ms
    Memory:9028 kb
****************************************************************/

/**************************************************************
    Problem: 3262
    User: MiEcoku
    Language: C++
    Result: Accepted
    Time:3416 ms
    Memory:6296 kb
****************************************************************/

#include <cstdio>
#include <algorithm>
using namespace std;
#define mid ( l + r >> 1)
#define lowbit(x) ( x & -x)

struct GG {
    int x, y, z, id, w;
    void get () {
        scanf("%d%d%d", &x, &y, &z);
    }
}a[], b[], T[];

], k, tim, mark[];
int query(int x, int K) {
    ;
    ; x -= lowbit(x)) if( mark[x] == K) ans += dis[x];
    return ans;
}
void add(int x, int y, int K) {
    for ( ; x <= k; x += lowbit(x)) if( mark[x] == K) dis[x] += y;
    else mark[x] = K, dis[x] = y;
}

bool cmp1(GG a, GG b) { return a.x < b.x || (a.x == b.x && a.y < b.y) || (a.x == b.x && a.y == b.y && a.z < b.z); }
bool cmp2(GG a, GG b) { return a.y < b.y || (a.y == b.y && a.z < b.z); }

];
void cdq(int l, int r) {
    , r);
    , cnt = ; ++ tim;
    for ( int i = l; i <= mid; i ++) {
        while( b[q].y < b[i].y && q <= r) ans[b[q].id] += query(b[q].z, tim), T[++ cnt] = b[q], q ++;
        add(b[i].z, b[i].w, tim); T[++ cnt] = b[i];
    }
    while( q <= r) ans[b[q].id] += query(b[q].z, tim), T[++ cnt] = b[q], q ++;
    cnt = ;
    for ( int i = l; i <= r; ++ i) b[i] = T[++ cnt];
}

];
int main() {
    scanf("%d%d", &_, &k);
    ; i <= _; i ++) a[i].get();
    sort( a+, a++_, cmp1);
    ; i <= _; i ++) {
        cnt ++;
        ].x || a[i].y != a[i+].y || a[i].z != a[i+].z)
        b[++ n] = a[i], b[n].w = cnt, cnt = , b[n].id = n;
    }
    cdq(, n);
    ; i <= n; i ++)
        d[ans[b[i].id]+b[i].w-] += b[i].w;
    ; i < _; i ++) printf("%d\n", d[i]);
}

博主因为傻逼不知道这么写然后考试写的KT-tree被卡了


[BZOJ 3262]陌上开花的更多相关文章

  1. bzoj 3262 陌上花开 - CDQ分治 - 树状数组

    Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当 ...

  2. BZOJ.3262.陌上花开([模板]CDQ分治 三维偏序)

    题目链接 BZOJ3262 洛谷P3810 /* 5904kb 872ms 对于相邻x,y,z相同的元素要进行去重,并记录次数算入贡献(它们之间产生的答案是一样的,但不去重会..) */ #inclu ...

  3. Luogu 3810 & BZOJ 3262 陌上花开/三维偏序 | CDQ分治

    Luogu 3810 & BZOJ 3263 陌上花开/三维偏序 | CDQ分治 题面 \(n\)个元素,每个元素有三个值:\(a_i\), \(b_i\) 和 \(c_i\).定义一个元素的 ...

  4. 【BZOJ 3262】 3262: 陌上花开 (CDQ分治)

    3262: 陌上花开 Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A ...

  5. BZOJ 3262 陌上花开 ——CDQ分治

    [题目分析] 多维问题,我们可以按照其中一维排序,然后把这一维抽象的改为时间. 然后剩下两维,就像简单题那样,排序一维,树状数组一维,按照时间分治即可. 挺有套路的一种算法. 时间的抽象很巧妙. 同种 ...

  6. bzoj 3262 陌上花开

    本质是一个三维偏序,一位排序后cdq分治,一维在子函数里排序,一维用树状数组维护. 把三维相等的合并到一个里面. #include<iostream> #include<cstdio ...

  7. BZOJ 3262 陌上花开 CDQ分治

    = =原来复杂度还是nlog^2(n) Orz 被喷了 #include<cstdio> #include<cstdlib> #include<algorithm> ...

  8. BZOJ 3262: 陌上花开 [CDQ分治 三维偏序]

    Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当 ...

  9. 【刷题】BZOJ 3262 [HNOI2008]GT考试

    Description 阿申准备报名参加GT考试,准考证号为N位数X1X2....Xn(0<=Xi<=9),他不希望准考证号上出现不吉利的数字. 他的不吉利数学A1A2...Am(0< ...

随机推荐

  1. linux设置rsync+inotify实时同步文件

    linux设置rsync+inotify实时同步文件   应用场景: 同步接收方:test01 接收目录:/opt/software/test/a/ 同步发起方:test02 同步目录:/opt/so ...

  2. memcache 随笔

    第一次用可能有很多不足的地方  以后慢慢改进. memcache  是一个简单的键/值对    是通过键和值储存信息到memcache中 ,通过特定的键请求来返回信息. 信息会无限期的保留在内存中 : ...

  3. 30.MIN() 函数

    MIN() 函数 MIN 函数返回一列中的最小值.NULL 值不包括在计算中. SQL MIN() 语法 SELECT MIN(column_name) FROM table_name 注释:MIN ...

  4. jqgrid常用操作

    .jqgrid控件列在需要的地方加上edittable=true <asp:JQGrid runat=" DataUrl="/ccr/CcrCompanyPromoterMa ...

  5. 2.2开源的魅力:编译opencv源代码

    1.下载安装CMake 要在Windows平台下生成opencv的解决方案,需要一个名为CMake的开源软件.CMake的全称是crossplatform make.它是一个跨平台的安装(编译)工具, ...

  6. 原生ajax访问服务器所展现的现象

    <!DOCTYPE html><html><head><meta charset="UTF-8"><title>ajax ...

  7. C# 操作Excel基础篇(读取Excel、写入Excel)

    注意事项:Excel的数据表中最多只能储存65535行数据,超出后,需要将数据分割开来进行储存.同时对于Excel中的乱码象限,是由于编码的错误方式导致引起的! 一.读取Excel数据表,获得Data ...

  8. (转)每位设计师都应该拥有的50个CSS代码片段

    原文地址:http://www.cnblogs.com/fengyuqing/archive/2013/06/15/css_50.html 面对每年如此多的 新趋势 ,保持行业的领先是个很困难问题. ...

  9. 理解java中的值传递与“引用传递”

    额....java中其实没有引用传递 对于引用类型 ,在调用方法后,直接拷贝了引用的副本,但是它们指向了相同的堆地址,所以看起来像引用传递,但其实是值传递,只不过传递的引用的副本. 说一说为什么Str ...

  10. CentOS7-扩容挂载磁盘

    1.1查看新磁盘,可以看到/dev/sdb是新的未挂载的磁盘: [root@localhost ~]# fdisk -l 1.2硬盘分区 ,进入fdisk模式 进入fdisk模式 [root@loca ...