题意

题目链接

Sol

这题没有想象中的那么难,但也绝对不简单。

首先把所有的询问离线,按照出现的顺序。维护时间轴来处理每个询问

对于每个询问\((x_i, y_i)\),可以二分答案\(mid\)。

问题转化为对于所有\(a_i \leqslant y_i \leqslant b_i\)的商店,\((x - mid, x + mid)\)内是否所有类型的商店都出现过

若都出现过,减小\(mid\),否则增大\(mid\)

现在有两个问题:

  1. 如何维护当前可行的所有商店,以及我们需要的信息

  2. 如何判断\((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)的更多相关文章

  1. 洛谷P3313 [SDOI2014]旅行(树链剖分 动态开节点线段树)

    题意 题目链接 Sol 树链剖分板子 + 动态开节点线段树板子 #include<bits/stdc++.h> #define Pair pair<int, int> #def ...

  2. 洛谷P3120 [USACO15FEB]牛跳房子(动态开节点线段树)

    题意 题目链接 Sol \(f[i][j]\)表示前\(i\)行\(j\)列的贡献,转移的时候枚举从哪里转移而来,复杂度\(O(n^4)\) 然后考虑每一行的贡献,动态开节点线段树维护一下每种颜色的答 ...

  3. 洛谷P3994 Highway(树形DP+斜率优化+可持久化线段树/二分)

    有点类似NOI2014购票 首先有方程$f(i)=min\{f(j)+(dep_i-dep_j)*p_i+q_i\}$ 这个显然是可以斜率优化的... $\frac {f(j)-f(k)}{dep_j ...

  4. 洛谷P3960 列队(动态开节点线段树)

    题意 题目链接 Sol 看不懂splay..,看不懂树状数组... 只会暴力动态开节点线段树 观察之后不难发现,我们对于行和列需要支持的操作都是相同的:找到第\(k\)大的元素并删除,在末尾插入一个元 ...

  5. 洛谷P4344 脑洞治疗仪 [SHOI2015] 线段树+二分答案/分块

    !!!一道巨恶心的数据结构题,做完当场爆炸:) 首先,如果你用位运算的时候不小心<<打成>>了,你就可以像我一样陷入疯狂的死循环改半个小时 然后,如果你改出来之后忘记把陷入死循 ...

  6. 洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树

    洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树 题目描述 方伯伯正在做他的 \(Oj\) .现在他在处理 \(Oj\) 上的用户排名问题. \(Oj\) 上注册了 \(n\) 个用户 ...

  7. 洛谷 P3258 [JLOI2014]松鼠的新家(树链剖分)

    题目描述松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前来 ...

  8. 洛谷 P3258 [JLOI2014]松鼠的新家 解题报告

    P3258 [JLOI2014]松鼠的新家 题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他 ...

  9. 洛谷P3258 [JLOI2014]松鼠的新家(树上差分+树剖)

    题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前 ...

随机推荐

  1. SDUT OJ 数据结构实验之二叉树七:叶子问题

    数据结构实验之二叉树七:叶子问题 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Discuss Problem Descri ...

  2. 在Pd中取消Code Name 同步

    以前记得现在忘记了,好不容易找回来,记住备忘吧.  

  3. .Net Core 使用swagger UI

    swagger UI 第一步:首先添加包Swashbuckle.AspNetCore (可通过微软添加包命令Install-Package 包名进行添加,也可以通过管理NuGet程序包进行添加) 第二 ...

  4. python基础02—运算符与流程控制

    运算符与流程控制 运算符 赋值运算 用'='表示,'='的左边只能是变量 算术运算 +.-.*:加.减.乘 /:除法运算,运算结果为浮点数 //:除法运算,运算结果为整数(商) %:求余 **:求幂 ...

  5. python学习之路---day26

    网络的基本知识点 一:网络通信原理 连接两台计算机之间的Internet之间的协议一系列协议为互联网协议 互联网协议的功能是:定义计算机如何接入Internet,以及Internet的计算机通信标准 ...

  6. LeetCode记录之28——Implement strStr()

    Implement strStr(). Returns the index of the first occurrence of needle in haystack, or -1 if needle ...

  7. asp.net 同时执行js事件和代码事件 导出 excel

     onclick="return bnQuery_onclick()" onserverclick="bnQuery_ServerClick"   public ...

  8. bzoj3262 陌上花开 cdq分治(入门)

    题目传送门 思路:cdq分治处理偏序关系的模板题,主要就是学cdq分治吧,还在入门中. 代码其实也很好理解,记得树状数组操作的上限是 z的最大值,不是n的最大值,这个细节wa了好久. #include ...

  9. D. Magic Gems(矩阵快速幂 || 无敌杜教)

    https://codeforces.com/contest/1117/problem/D 题解:有一些魔法宝石,魔法宝石可以分成m个普通宝石,每个宝石(包括魔法宝石)占用1个空间,让你求占用n个空间 ...

  10. XAML 绑定和结构体不得不说的问题

    遇见一个问题 如果用一个结构体struct.再用一个ListView,然后使用绑定. <Window x:Class="WpfApp1.MainWindow" xmlns=& ...