前言

DennyQi太巨了!

定义一个点\(a\),\(a_x\)表示\(a\)在第\(x\)维空间上的坐标值

题解

这题的思路珂以说非常巧妙(原谅我又用了这个"珂"),

我们知道曼哈顿距离是\(\sum|a_i-b_i|\),\(|a_i-b_i|\)其实也珂以看作是\((a_i-b_i)\)和\((b_i-a_i)\)中较大的那个。

根据上面的分析曼哈顿距离珂以看作是\(\sum max(a_i-b_i,b_i-a_i)\),

继续分析珂以得出,每个点在每一维度上要应用的无非只有两种情况\(a_i\),\(-a_i\)。

由于区间内取两点求最小值要求每个点都是完整的(就是说一旦选取了该点那么必定会用到该点所有维度上的坐标),那么也就意味着对于一个点,它最多可能(仅为可能)用到的状态会是\(2^k\)次方个。

本题坐标只有5维,电脑不是人脑,那么显然我们珂以枚举解决以上问题。

那么求曼哈顿距离的时候便利所有\(a_i\)的正负性,显然若\(a_i\)为正,\(b_i\)即负;\(a_i\)为负,\(b_i\)为正。

如果用一个二进制状态来压缩,1表示\(a_i\)为正,0表示\(a_i\)为负,显然任意一组关于\(a\)的状态,记为\(sta\),

对应的\(b\)的装态表示为\((((2^k) - 1) - sta)\)也珂以记作\((((2^k) - 1)\ \textbf{xor}\ sta)\)。

那么用一个线段树维护,每一个节点表示对应的区间\([l,r]\)内的曼哈顿距离最大值。

上传标记非常简单就是暴力取两个子节点,然后取对于每一种正负性的珂能,都取max即可。

inline void pushUp(int pos){
for (int i = 0; i < max_sta; ++i)
seg[pos].f[i] = max(seg[pos << 1].f[i], seg[pos << 1 | 1].f[i]);
}

同理应用于合并query时的左右子树的结果。

例子

如果您没有看懂上面的文字,我们不妨来举一个例子。

若\(k=3\)时有两个点\(a,b\)坐标分别记为\((1,2,3),(-1,2,4)\)

那么对于点a来说有\(2^3=8\)种状态,

即\((1,2,3),(1,2,-3),(1,-2,3),(1,-2,-3),\)

  \((-1,2,3),(-1,2,-3),(-1,-2,3),(-1,-2,-3)\)

同理b也有\(2^3=8\)种状态,对于这\(a,b\)的\(8\)种状态两两对应,也就是

\((1,2,3)\)对应\((-(-1),-2,-4)\dots\)这些互相对应的状态取max以后也就是 \(\sum|a_i-b_i|\)啦QAQ

代码

#include <cstdio>
#include <cstring>
#include <algorithm> using namespace std; struct Pos{
int f[32];
} seg[800005]; int n, k, max_sta; inline void pushUp(int pos){
for (int i = 0; i < max_sta; ++i)
seg[pos].f[i] = max(seg[pos << 1].f[i], seg[pos << 1 | 1].f[i]);
} int tmppos[5]; void build(int pos, int l, int r){
if (l == r){
for (int i = 0; i < k; ++i) scanf("%d", &tmppos[i]);
for (int i = 0; i < max_sta; ++i){
seg[pos].f[i] = 0;
for (int j = 0; j < k; ++j)
if (i & (1 << j))
seg[pos].f[i] += tmppos[j];
else
seg[pos].f[i] -= tmppos[j];
}
return ;
}
int mid = (l + r) >> 1;
build(pos << 1, l, mid), build(pos << 1 | 1, mid + 1, r);
pushUp(pos);
} inline void mrg(Pos &a, Pos b){
for (int i = 0; i < max_sta; ++i)
a.f[i] = max(a.f[i], b.f[i]);
} Pos query(int pos, int l, int r, int x, int y){
if (x <= l && r <= y) return seg[pos];
int mid = (l + r) >> 1;
Pos res;
if (x <= mid)
res = query(pos << 1, l, mid, x, y);
if (y > mid){
if (x <= mid)
mrg(res, query(pos << 1 | 1, mid + 1, r, x, y));
else
res = query(pos << 1 | 1, mid + 1, r, x, y);
}
return res;
} void modify(int pos, int l, int r, int x){
if (l == r){
for (int i = 0; i < max_sta; ++i){
seg[pos].f[i] = 0;
for (int j = 0; j < k; ++j)
if (i & (1 << j))
seg[pos].f[i] += tmppos[j];
else
seg[pos].f[i] -= tmppos[j];
}
return ;
}
int mid = (l + r) >> 1;
if (x <= mid) modify(pos << 1, l, mid, x);
else modify(pos << 1 | 1, mid + 1, r, x);
pushUp(pos);
} int main(){
scanf("%d %d", &n, &k); max_sta = 1 << k;
build(1, 1, n);
int q; scanf("%d", &q);
while (q--){
int op; scanf("%d", &op);
int i;
if (op == 1){
scanf("%d", &i);
for (int j = 0; j < k; ++j)
scanf("%d", &tmppos[j]);
modify(1, 1, n, i);
}
else if (op == 2){
int l, r; scanf("%d %d", &l, &r);
Pos res = query(1, 1, n, l, r);
int ans = 0;
for (int i = 0; i < (1 << (k - 1)); ++i)
ans = max(ans, res.f[i] + res.f[(max_sta - 1) ^ i]);
printf("%d\n", ans);
}
}
return 0;
}

[CF1093G]Multidimensional Queries 题解的更多相关文章

  1. [CF1093G]Multidimensional Queries

    [CF1093G]Multidimensional Queries 题目大意: \(k(k\le5)\)维空间中有\(n(n\le2\times10^5)\)个点.\(m\)次操作,操作包含一下两种: ...

  2. [CF1093G]Multidimensional Queries:线段树

    分析 非常有趣的一道题. 式子中的绝对值很难处理,但是我们发现: \[\sum_{i=1}^{k}|a_{x,i}-a_{y,i}|=\sum_{i=1}^{k}max(a_{x,i}-a_{y,i} ...

  3. CF 1093 G. Multidimensional Queries

    G. Multidimensional Queries 链接 分析: 考虑如何去掉绝对值符号. $\sum \limits_{i = 1}^{k} |a_{x, i} - a_{y, i}|$,由于k ...

  4. CF 1093G Multidimensional Queries——线段树(消去绝对值符号)

    题目:http://codeforces.com/contest/1093/problem/G 只好看看题解:https://codeforces.com/blog/entry/63877 主要是把绝 ...

  5. CF375D Tree and Queries 题解

    感觉CF的题目名都好朴素的样子 你谷链接 首先这题显然是个dsu on tree 但是我不会. 其次这题显然是个莫队.这我会啊! 然后会发现好像不是很对劲.因为每次询问都有一个k,貌似和传统的莫队数颜 ...

  6. POJ-2926-Requirements&&Educational Codeforces Round 56G. Multidimensional Queries 【哈夫曼距离】

    POJ2926 先学会这个哈夫曼距离的处理才能做 cf 的G #include <iostream> #include <stdio.h> #include <algor ...

  7. codeforces1093G Multidimensional Queries 【线段树】

    题目分析: 搜索2^k种情况,线段树分别处理就行了,正确性明显. 代码: #include<bits/stdc++.h> using namespace std; ; int n,k; ] ...

  8. CodeForces - 1093G:Multidimensional Queries (线段树求K维最远点距离)

    题意:给定N个K维的点,Q次操作,或者修改点的坐标:或者问[L,R]这些点中最远的点. 思路:因为最后一定可以表示维+/-(x1-x2)+/-(y1-y2)+/-(z1-z2)..... 所以我们可以 ...

  9. Multidimensional Queries(二进制枚举+线段树+Educational Codeforces Round 56 (Rated for Div. 2))

    题目链接: https://codeforces.com/contest/1093/problem/G 题目: 题意: 在k维空间中有n个点,每次给你两种操作,一种是将某一个点的坐标改为另一个坐标,一 ...

随机推荐

  1. 深入理解java:4.1. 框架编程之Spring MVC

    说到java的mvc框架,struts2和springmvc想必大家都知道, Spring MVC是当前最优秀的MVC框架,自从Spring 2.5版本发布后,由于支持注解配置,易用性有了大幅度的提高 ...

  2. 用SelectSingleNode()方法查找xml节点一直返回null

    代码使用如下 XmlNode root = xmlDoc.SelectSingleNode("Project"); 返回的root一直是null 查了xml文件中确实是有Proje ...

  3. PTA 7-20 表达式转换

    转自:https://www.cnblogs.com/yuxiaoba/p/8399934.html 算术表达式有前缀表示法.中缀表示法和后缀表示法等形式.日常使用的算术表达式是采用中缀表示法,即二元 ...

  4. 【Linux 网络编程】滑动窗口协议

    <1>通知接受窗口(rwnd): 预防应用程序发送的数据超过对方的缓冲区.接收方使用的流量控制<2>拥塞窗口(cwnd): 预防应用程序发送的数据超过网络所承受的能力.发送方使 ...

  5. 并发之AQS原理(二) CLH队列与Node解析

    并发之AQS原理(二) CLH队列与Node解析 1.CLH队列与Node节点 就像通常医院看病排队一样,医生一次能看的病人数量有限,那么超出医生看病速度之外的病人就要排队. 一条队列是队列中每一个人 ...

  6. numpy-添加操作大全

    合并 hstack(tup):按行合并 [前面有个 h,可以理解为 行,这样方便记忆] vstack(tup):按列合并 参数虽然是 tuple,但是 list 也行,可以合并2个或者多个数组. a= ...

  7. linux:用户和组文件解释(/etc/passwd、/etc/shadow、/etc/group、/etc/gshadow)

    一.用户文件:/etc/passwd [root@pinfun6 ~]# cat /etc/passwd root:x:0:0:root:/root:/bin/bash 1 2 3 4 5 6 7 | ...

  8. Jinja2 中文手册

    欢迎来到 Jinja2 Jinja2 是一个现代的,设计者友好的,仿照 Django 模板的 Python 模板语言. 它速度快,被广泛使用,并且提供了可选的沙箱模板执行环境保证安全: <tit ...

  9. luogu P4654 [CEOI2017]Mousetrap

    传送门 这里把终点设为根方便后续处理,那么目标就是要让老鼠走到根 首先考虑老鼠动不了的情况,这种情况下可以把从这个点到终点路径上的分支堵住,然后再疏通路径上的走过的边,可以发现这是这种情况下最优的决策 ...

  10. Linux系统,无法收到组播消息的问题

    解决办法: 做以下3个修改 1. /etc/sysctl.conf 文件中的 net.ipv4.conf.all.rp_filter 设置成0 2. sysctl -w net.ipv4.conf.a ...