洛谷P4632 [APIO2018] New Home 新家(动态开节点线段树 二分答案 扫描线 set)
题意
Sol
这题没有想象中的那么难,但也绝对不简单。
首先把所有的询问离线,按照出现的顺序。维护时间轴来处理每个询问
对于每个询问\((x_i, y_i)\),可以二分答案\(mid\)。
问题转化为对于所有\(a_i \leqslant y_i \leqslant b_i\)的商店,\((x - mid, x + mid)\)内是否所有类型的商店都出现过
若都出现过,减小\(mid\),否则增大\(mid\)
现在有两个问题:
如何维护当前可行的所有商店,以及我们需要的信息
如何判断\((x - mid, x + mid)\)内是否所有类型的商店都出现过
显然问题1依赖于问题2
对于第二个问题,一种方法是直接树套树区间数颜色,另一个巧妙的方法是定义\(pre_i\)表示和\(i\)号位置类型相同的商店中,\(x\)坐标小于\(i\)的第一个位置
若\(mid\)是合法的,一定存在一个位置\(p \in (x + mid + 1, N)\)满足\(pre_p < x - mid\)
那么直接用线段树维护\(pre\)的最小值即可。
线段树应该动态开点,当然你也可以头铁写离散化然后就需要考虑各种边界问题。。
问题1实际上我们只需要维护好\(pre\)即可
一个显然的想法是直接开\(30w\)个set维护每个类型
加入 / 删除的时候只会影响到\(3\)个位置
时间复杂度:\(O(nlog^2n)\),单次询问的复杂度为\(O(logn)\)
需要注意一个细节,由于是在线段树上二分,所以二分的边界应该与线段树相同
#include<bits/stdc++.h>
#define mit multiset<int>::iterator
using namespace std;
const int MAXN = 3e5 + 10, L = 1e9, Lim = (1 << 22) + 1;
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int N, K, Q, cnt, rt, ans[MAXN];
multiset<int> op[MAXN];//val of each type
multiset<int> s[Lim];//
int Mn[Lim], ls[Lim], rs[Lim];
struct Query {
int ti, opt, x;// time type pos
bool operator < (const Query &rhs) const {
return ti == rhs.ti ? opt < rhs.opt : ti < rhs.ti;
}
}q[MAXN * 3 + 10];
int tot = 0;
void Erase(multiset<int> &s, int &val) {
mit t = s.find(val);
if(t != s.end()) s.erase(t);
}
void update(int k) {
Mn[k] = min(Mn[ls[k]], Mn[rs[k]]);
}
void Insert(int &k, int l, int r, int x, int New, int Old) {
if(!k) k = ++tot;
if(l == r) {
if(New) s[k].insert(New);
if(Old) Erase(s[k], Old);
Mn[k] = (s[k].empty() ? L : *s[k].begin()); return ;
}
int mid = l + r >> 1;
if(x <= mid) Insert(ls[k], l, mid, x, New, Old);
else Insert(rs[k], mid + 1, r, x, New, Old);
update(k);
}
int query(int x) {
int l = 0, r = L, mid, now = rt, lim = L, ans;
while(l < r) {
int mid = l + r >> 1, mn = min(Mn[rs[now]], lim);
if((x > mid) || (mid - x < x - mn))
l = mid + 1, now = rs[now], ans = mid;
else r = mid, now = ls[now], lim = mn;
}
return l - x;
}
N = read(); K = read(); Q = read(); Mn[0] = L;
for(int i = 1; i <= N; i++) {
int x = read(), t = read(), a = read(), b = read();
q[++cnt] = (Query) {a, t, x};
q[++cnt] = (Query) {b + 1, -t, x};
}
for(int i = 1; i <= Q; i++) {
int x = read(), y = read();
q[++cnt] = (Query) {y, N + i, x};
}
sort(q + 1, q + cnt + 1); int Now = 0;// now type num
for(int i = 1; i <= K; i++) op[i].insert(L), op[i].insert(-L), Insert(rt, 0, L, L, -L, 0);
for(int i = 1; i <= cnt; i++) {
int ty = q[i].opt;
if(ty > N)
ans[ty - N] = Now < K ? - 1 : query(q[i].x);
else if(ty > 0) { // add
mit t = op[ty].upper_bound(q[i].x), r = t--;
Insert(rt, 0, L, *r, q[i].x, *t);
Insert(rt, 0, L, q[i].x, *t, 0);
if(op[ty].size() == 2) Now++;
op[ty].insert(q[i].x);
} else {
ty = -ty;
mit t = op[ty].upper_bound(q[i].x), r = t--; t--;
Insert(rt, 0, L, *r, *t, q[i].x);
Insert(rt, 0, L, q[i].x, 0, *t);
Erase(op[ty], q[i].x);
if(op[ty].size() == 2) Now--;
}
}
for(int i = 1; i <= Q; i++) printf("%d\n", ans[i]);
return 0;
}
洛谷P4632 [APIO2018] New Home 新家(动态开节点线段树 二分答案 扫描线 set)的更多相关文章
- 洛谷P3313 [SDOI2014]旅行(树链剖分 动态开节点线段树)
题意 题目链接 Sol 树链剖分板子 + 动态开节点线段树板子 #include<bits/stdc++.h> #define Pair pair<int, int> #def ...
- 洛谷P3120 [USACO15FEB]牛跳房子(动态开节点线段树)
题意 题目链接 Sol \(f[i][j]\)表示前\(i\)行\(j\)列的贡献,转移的时候枚举从哪里转移而来,复杂度\(O(n^4)\) 然后考虑每一行的贡献,动态开节点线段树维护一下每种颜色的答 ...
- 洛谷P3994 Highway(树形DP+斜率优化+可持久化线段树/二分)
有点类似NOI2014购票 首先有方程$f(i)=min\{f(j)+(dep_i-dep_j)*p_i+q_i\}$ 这个显然是可以斜率优化的... $\frac {f(j)-f(k)}{dep_j ...
- 洛谷P3960 列队(动态开节点线段树)
题意 题目链接 Sol 看不懂splay..,看不懂树状数组... 只会暴力动态开节点线段树 观察之后不难发现,我们对于行和列需要支持的操作都是相同的:找到第\(k\)大的元素并删除,在末尾插入一个元 ...
- 洛谷P4344 脑洞治疗仪 [SHOI2015] 线段树+二分答案/分块
!!!一道巨恶心的数据结构题,做完当场爆炸:) 首先,如果你用位运算的时候不小心<<打成>>了,你就可以像我一样陷入疯狂的死循环改半个小时 然后,如果你改出来之后忘记把陷入死循 ...
- 洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树
洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树 题目描述 方伯伯正在做他的 \(Oj\) .现在他在处理 \(Oj\) 上的用户排名问题. \(Oj\) 上注册了 \(n\) 个用户 ...
- 洛谷 P3258 [JLOI2014]松鼠的新家(树链剖分)
题目描述松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前来 ...
- 洛谷 P3258 [JLOI2014]松鼠的新家 解题报告
P3258 [JLOI2014]松鼠的新家 题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他 ...
- 洛谷P3258 [JLOI2014]松鼠的新家(树上差分+树剖)
题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前 ...
随机推荐
- 伪元素改变date类型input框的默认样式实例页面
CSS代码: ::-webkit-datetime-edit { padding: 1px; background: url(/study/image/selection.gif); } ::-web ...
- shell-004:检测机器存活或者网络陡动情况!
如下图情况,我们监测的就是此数据,当大于50%了,我们就可以设置告警等! #!/bin/bash # 用ping检测一台机器的存活或者网络波动情况 # 检测机器的丢包率来检测网络波动情况!! n=`p ...
- CF914E Palindromes in a Tree(点分治)
题面 洛谷 CF 题解 题意:给你一颗 n 个顶点的树(连通无环图).顶点从 1 到 n 编号,并且每个顶点对应一个在'a'到't'的字母. 树上的一条路径是回文是指至少有一个对应字母的排列为回文. ...
- 洛谷 P3275 [SCOI2011]糖果
题目链接 题解 差分约束 学过的应该都会做 不会的自行百度,这里不多讲 opt=1 连一条长度为0的双向边 opt=2 (u->v) \(len=-1\) opt=3 (v->u) \(l ...
- 洛谷 P4859 && BZOJ3622: 已经没有什么好害怕的了
题目描述 给出 \(n\) 个数 \(a_i\) ,以及 \(n\) 个数 \(b_i\) ,要求两两配对使得 \(a>b\) 的对数减去 \(a<b\) 的对数等于 \(k\) . ...
- codeforces 1100F Ivan and Burgers 线性基 离线
题目传送门 题意: 给出 n 个数,q次区间查询,每次查询,让你选择任意个下标为 [ l , r ] 区间内的任意数,使这些数异或起来最大,输出最大值. 思路:离线加线性基. 线性基学习博客1 线性基 ...
- SQL中的正则表达式
[转自] http://blog.csdn.net/weiwenhp/article/details/6943834 当我们要进行一些简单的糊涂查询时用百分号(%),通配符(_)就可以了.其中%表达任 ...
- 搭建Redis报错
2018-10-26 报错信息 You need tcl 8.5 or newer in order to run the Redis test 原因 缺少 tcl 插件 解决方式 wget http ...
- 公钥,私钥,数字签名,SSL的基本概念
一,公钥私钥 1,公钥和私钥成对出现 2,公开的密钥叫公钥,只有自己知道的叫私钥 3,用公钥加密的数据只有对应的私钥可以 解密 4,用私钥加密的数据只有对应的公钥可以解密 5,如果可以用公钥解密,则必 ...
- http请求报文和响应报文(2)
接上篇: 3.回应报文 理解回应报文,首先要弄清回应报文中的状态码. 相比于请求报文,对于响应报文,个人觉得还蛮有趣的. 主要由三部分组成:协议版本.状态码.状态码描述 3.1状态码 **常见的状态码 ...