题目链接

传送门

思路

这个题在\(BZOJ\)上有个二维平面的版本(\(BZOJ2716\)天使玩偶),不过是权限题因此就不附带链接了,我也只是在算法进阶指南上看到过,那个题的写法是\(CDQ\),然后比赛开始半个小时我就开始写\(CDQ\),\(T\)了之后冷静分析发现复杂度我少算了个\(log\),\(CDQ\)写这题的复杂度是\(nlog^3(n)\),然后就没思路了。

赛后看\(qls\)说用三维\(bit\)可以过后试了一下\(T\)了,然后发现\(qls\)的代码当时跑了\(937ms\)应该是卡过去的,感觉是\(vector\)常数大,但是想不出除\(vector\)的其他动态开全局数组大小的方法,最后疯狂交在\(T\)了一页后成功卡过去了,下面贴一下三维\(bit\)的代码和\(CDQ\)写法(对拍了很久貌似没问题,就当过了吧~)的代码。

这两份代码的主体思路就是拆绝对值符号,然后查询时(拿\(x_1\leq x2,y_1\leq y2,z_1\leq z_2\)举例,下标为\(2\)的是查询的点)\(|x_2-x_1|+|y_2-y_1|+|z_2-z_1|=(x_2+y_2+z_2)-(x_1+y_1+z_1)\),然后就是要查询\(x_1+y_1+z_1\)的最大值用树状数组维护即可,其他情况分别移动坐标即可。

update:发现题解里面贴的那份代码的三维\(bit\)写法贼牛逼,贴的代码就改成看了那个队的代码之后写的了。

代码

//三维bit
#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL; #define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define FIN freopen("/home/dillonh/CLionProjects/Dillonh/in.txt","r",stdin)
#define IO ios::sync_with_stdio(false),cin.tie(0) const double eps = 1e-8;
const int mod = 1000000007;
const int maxn = 800000 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL; int n, m, h, q, op, x, y, z; struct BIT {
int a[maxn]; int gethash(int x, int y, int z) {
return x * h * m + y * h + z;
} void init() {
for(int i = 0; i <= n; ++i) {
for(int j = 0; j <= m; ++j) {
for(int k = 0; k <= h; ++k) {
a[gethash(i, j, k)] = 0;
}
}
}
} void update(int x, int y, int z) {
for(int i = x; i <= n; i += lowbit(i)) {
for(int j = y; j <= m; j += lowbit(j)) {
for(int k = z; k <= h; k += lowbit(k)) {
int num = gethash(i, j, k);
a[num] = max(a[num], x + y + z);
}
}
}
} int query(int x, int y, int z) {
int ans = 0;
for(int i = x; i > 0; i -= lowbit(i)) {
for(int j = y; j > 0; j -= lowbit(j)) {
for(int k = z; k > 0; k -= lowbit(k)) {
ans = max(ans, a[gethash(i, j, k)]);
}
}
}
if(ans == 0) return inf;
return x + y + z - ans;
}
}bit[8]; int main() {
scanf("%d%d%d%d", &n, &m, &h, &q);
n += 1, m += 1, h += 1;
for(int i = 0; i < 8; ++i) bit[i].init();
for(int i = 1; i <= q; ++i) {
scanf("%d%d%d%d", &op, &x, &y, &z);
if(op == 1) {
bit[1].update(x, y, z);
bit[2].update(x, y, h - z);
bit[3].update(x, m - y, z);
bit[4].update(n - x, y, z);
bit[5].update(n - x, m - y, z);
bit[6].update(n - x, y, h - z);
bit[7].update(x, m - y, h - z);
bit[0].update(n - x, m - y, h - z);
} else {
int ans = inf;
ans = min(ans, bit[1].query(x, y, z));
ans = min(ans, bit[2].query(x, y, h - z));
ans = min(ans, bit[3].query(x, m - y, z));
ans = min(ans, bit[4].query(n - x, y, z));
ans = min(ans, bit[5].query(n - x, m - y, z));
ans = min(ans, bit[6].query(n - x, y, h - z));
ans = min(ans, bit[7].query(x, m - y, h - z));
ans = min(ans, bit[0].query(n - x, m - y, h - z));
printf("%d\n", ans);
}
}
return 0;
}
//CDQ
#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL; #define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define FIN freopen("/home/dillonh/CLionProjects/Dillonh/in.txt","r",stdin)
#define IO ios::sync_with_stdio(false),cin.tie(0) const double eps = 1e-8;
const int mod = 1000000007;
const int maxn = 100001;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL; int n, m, h, q, op, x, y, z;
int tree[maxn], ans[maxn]; struct node {
int id, x, y, z, op, val, flag;
bool operator < (const node& a) const {
return id < a.id;
}
}a[maxn], tmp[maxn], pp[maxn]; void add(int x, int val) {
while(x <= h) {
tree[x] = max(tree[x], val);
x += lowbit(x);
}
} int query(int x) {
int ans = 0;
while(x) {
ans = max(ans, tree[x]);
x -= lowbit(x);
}
if(ans == 0) ans = -inf;
return ans;
} void del(int x) {
while(x <= h + 1) {
tree[x] = 0;
x += lowbit(x);
}
} void cdq2(int l, int r) {
if(l == r) return;
int mid = (l + r) >> 1;
cdq2(l, mid), cdq2(mid + 1, r);
int ls = l, rs = mid + 1, cnt = l;
for(; rs <= r; ++rs) {
for(; ls <= mid && tmp[ls].y <= tmp[rs].y; ++ls) {
if(tmp[ls].op == 1 && tmp[ls].flag) {
add(tmp[ls].z, tmp[ls].val);
}
}
if(!tmp[rs].flag && tmp[rs].op == 2) ans[tmp[rs].id] = min(ans[tmp[rs].id], tmp[rs].val - query(tmp[rs].z));
}
--ls;
while(ls >= l) {
if(tmp[ls].op == 1 && tmp[ls].flag) {
del(tmp[ls].z);
}
--ls;
}
ls = l, rs = mid + 1;
while(ls <= mid && rs <= r) {
if(tmp[ls].y < tmp[rs].y) {
pp[cnt++] = tmp[ls++];
} else if(tmp[ls].y > tmp[rs].y) {
pp[cnt++] = tmp[rs++];
} else if(tmp[ls].z <= tmp[rs].z) {
pp[cnt++] = tmp[ls++];
} else {
pp[cnt++] = tmp[rs++];
}
}
while(ls <= mid) pp[cnt++] = tmp[ls++];
while(rs <= r) pp[cnt++] = tmp[rs++];
for(int i = l; i <= r; ++i) tmp[i] = pp[i];
} void cdq1(int l, int r) {
if(l == r) return;
int mid = (l + r) >> 1;
cdq1(l, mid), cdq1(mid + 1, r);
int ls = l, rs = mid + 1, cnt = l;
while(ls <= mid && rs <= r) {
if(a[ls].x < a[rs].x) {
tmp[cnt] = a[ls++];
tmp[cnt++].flag = 1;
} else if(a[ls].x > a[rs].x) {
tmp[cnt] = a[rs++];
tmp[cnt++].flag = 0;
} else if(a[ls].y < a[rs].y) {
tmp[cnt] = a[ls++];
tmp[cnt++].flag = 1;
} else if(a[ls].y > a[rs].y) {
tmp[cnt] = a[rs++];
tmp[cnt++].flag = 0;
} else if(a[ls].z <= a[rs].z) {
tmp[cnt] = a[ls++];
tmp[cnt++].flag = 1;
} else {
tmp[cnt] = a[rs++];
tmp[cnt++].flag = 0;
}
}
while(ls <= mid) {
tmp[cnt] = a[ls++];
tmp[cnt++].flag = 1;
}
while(rs <= r) {
tmp[cnt] = a[rs++];
tmp[cnt++].flag = 0;
}
for(int i = l; i <= r; ++i) a[i] = tmp[i];
cdq2(l, r);
} int main() {
#ifndef ONLINE_JUDGE
FIN;
#endif
scanf("%d%d%d%d", &n, &m, &h, &q);
n += 1, m += 1, h += 1;
for(int i = 1; i <= q; ++i) {
scanf("%d%d%d%d", &op, &x, &y, &z);
a[i] = {i, x, y, z, op, 0, 0};
}
//x,y,z
for(int i = 1; i <= q; ++i) {
ans[i] = inf;
a[i].val = a[i].x + a[i].y + a[i].z, a[i].flag = 0;
}
cdq1(1, q); //x,y,-z
for(int i = 1; i <= q; ++i) {
a[i].z = h - a[i].z;
a[i].val = a[i].x + a[i].y + a[i].z, a[i].flag = 0;
}
sort(a + 1, a + q + 1);
cdq1(1, q); //x,-y,z
for(int i = 1; i <= q; ++i) {
a[i].z = h - a[i].z;
a[i].y = m - a[i].y;
a[i].val = a[i].x + a[i].y + a[i].z, a[i].flag = 0;
}
sort(a + 1, a + q + 1);
cdq1(1, q); //-x,y,z
for(int i = 1; i <= q; ++i) {
a[i].y = m - a[i].y;
a[i].x = n - a[i].x;
a[i].val = a[i].x + a[i].y + a[i].z, a[i].flag = 0;
}
sort(a + 1, a + q + 1);
cdq1(1, q); //-x,-y,z
for(int i = 1; i <= q; ++i) {
a[i].y = m - a[i].y;
a[i].val = a[i].x + a[i].y + a[i].z, a[i].flag = 0;
}
sort(a + 1, a + q + 1);
cdq1(1, q); //-x,y,-z
for(int i = 1; i <= q; ++i) {
a[i].y = m - a[i].y;
a[i].z = h - a[i].z;
a[i].val = a[i].x + a[i].y + a[i].z, a[i].flag = 0;
}
sort(a + 1, a + q + 1);
cdq1(1, q); //x,-y,-z
for(int i = 1; i <= q; ++i) {
a[i].x = n - a[i].x;
a[i].y = m - a[i].y;
a[i].val = a[i].x + a[i].y + a[i].z, a[i].flag = 0;
}
sort(a + 1, a + q + 1);
cdq1(1, q); //-x,-y,-z
for(int i = 1; i <= q; ++i) {
a[i].x = n - a[i].x;
a[i].val = a[i].x + a[i].y + a[i].z, a[i].flag = 0;
}
sort(a + 1, a + q + 1);
cdq1(1, q); sort(a + 1, a + q + 1);
for(int i = 1; i <= q; ++i) {
if(a[i].op == 2) {
printf("%d\n", ans[i]);
}
}
return 0;
}

Distance(2019年牛客多校第八场D题+CDQ+树状数组)的更多相关文章

  1. Explorer(2019年牛客多校第八场E题+线段树+可撤销并查集)

    题目链接 传送门 题意 给你一张无向图,每条边\(u_i,v_i\)的权值范围为\([L_i,R_i]\),要经过这条边的条件是你的容量要在\([L_i,R_i]\),现在问你你有多少种容量使得你可以 ...

  2. 2019牛客多校第七场 F Energy stones 树状数组+算贡献转化模拟

    Energy stones 题意 有n块石头,每块有初始能量E[i],每秒石头会增长能量L[i],石头的能量上限是C[i],现有m次时刻,每次会把[s[i],t[i]]的石头的能量吸干,问最后得到了多 ...

  3. 2019牛客多校第八场 F题 Flowers 计算几何+线段树

    2019牛客多校第八场 F题 Flowers 先枚举出三角形内部的点D. 下面所说的旋转没有指明逆时针还是顺时针则是指逆时针旋转. 固定内部点的答案的获取 anti(A)anti(A)anti(A)或 ...

  4. 2020牛客多校第八场K题

    __int128(例题:2020牛客多校第八场K题) 题意: 有n道菜,第i道菜的利润为\(a_i\),且有\(b_i\)盘.你要按照下列要求给顾客上菜. 1.每位顾客至少有一道菜 2.给顾客上菜时, ...

  5. 2019年牛客多校第四场 B题xor(线段树+线性基交)

    题目链接 传送门 题意 给你\(n\)个基底,求\([l,r]\)内的每个基底是否都能异或出\(x\). 思路 线性基交板子题,但是一直没看懂咋求,先偷一份咖啡鸡板子写篇博客吧~ 线性基交学习博客:传 ...

  6. Palindrome Mouse(2019年牛客多校第六场C题+回文树+树状数组)

    目录 题目链接 题意 思路 代码 题目链接 传送门 题意 问\(s\)串中所有本质不同的回文子串中有多少对回文子串满足\(a\)是\(b\)的子串. 思路 参考代码:传送门 本质不同的回文子串肯定是要 ...

  7. generator 1(2019年牛客多校第五场B题+十进制矩阵快速幂)

    目录 题目链接 思路 代码 题目链接 传送门 思路 十进制矩阵快速幂. 代码 #include <set> #include <map> #include <deque& ...

  8. Find the median(2019年牛客多校第七场E题+左闭右开线段树)

    题目链接 传送门 题意 每次往集合里面添加一段连续区间的数,然后询问当前集合内的中位数. 思路 思路很好想,但是卡内存. 当时写的动态开点线段树没卡过去,赛后机房大佬用动态开点过了,\(tql\). ...

  9. 2019年牛客多校第三场 F题Planting Trees(单调队列)

    题目链接 传送门 题意 给你一个\(n\times n\)的矩形,要你求出一个面积最大的矩形使得这个矩形内的最大值减最小值小于等于\(M\). 思路 单调队列滚动窗口. 比赛的时候我的想法是先枚举长度 ...

随机推荐

  1. 应用JWT进行用户认证及Token的刷新

    本文将通过实际的例子来演示如何在ASP.NET Core中应用JWT进行用户认证以及Token的刷新方案(ASP.NET Core 系列目录) 一.什么是JWT? JWT(json web token ...

  2. 每月IT摘录201911

    技术 1.以 MySQL 的 InnoDB 引擎为例,由于 MySQL 中有两套日志机制,一套是存储层的 redo log,另一套是 server 层的 binlog,每次更新数据都要对两个日志进行更 ...

  3. JS数据结构第一篇---算法之复杂度判断

    1.算法:算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作. 那么一个怎样的算法才能称得上是好算法,也就是说有没有什么标准来评判一个算法的好坏? 在此之 ...

  4. Java 中常见的 final 类

    Java 中常见的 final 类 java.lang 包 public final class Boolean extends Object implements Serializable, Com ...

  5. react项目中怎么使用http-proxy-middleware反向代理跨域

    第一步 安装 http-proxy-middleware npm install http-proxy-middleware 我们这里面请求用的axios,在将axios安装一下 npm instal ...

  6. excel 使用

    列于列拼接

  7. 软件——解决Modelsim10.1d窗口不停弹出问题(一直弹窗)

    博主在编写Verilog HDL时需要用到Modelsim,于是博主便安装了Modelsim10.1d,然后兴高采烈打开准备跑仿真时,打开软件发现Modelsim10.1d的各种窗口在不停弹出,终止进 ...

  8. Azkaban 3.x 编译及部署

    一.Azkaban 源码编译 1.1 下载并解压 Azkaban 在 3.0 版本之后就不提供对应的安装包,需要自己下载源码进行编译. 下载所需版本的源码,Azkaban 的源码托管在 GitHub ...

  9. 4、VUE生命周期

    下面是分步骤解释vue生命周期 1.开始:new Vue() 创建vue对象过程还是比较繁琐的,所以创建vue对象是异步执行的. 回调函数:beforeCreate 2.Observe Data 监控 ...

  10. 树莓派Raspbian系统密码

    树莓派Raspbian系统密码 树莓派Raspbian系统默认登录用户名为pi,该账户默认密码是raspberry(可在raspi-config中修改). 树莓派的Raspbian系统root用户默认 ...