「APIO2018新家」

题目描述

五福街是一条笔直的道路,这条道路可以看成一个数轴,街上每个建筑物的坐标都可以用一个整数来表示。小明是一位时光旅行者,他知道在这条街上,在过去现在和未来共有 \(n\)个商店出现。第 \(i\) 个商店可以使用四个整数 \(x_i, t_i, a_i, b_i\) 描述,它们分别表示:商店的坐标、商店的类型、商店开业的年份、商店关闭的年份。

小明希望通过时光旅行,选择一个合适的时间,住在五福街上的某个地方。他给出了一份他可能选择的列表,上面包括了 \(q\) 个询问,每个询问用二元组(坐标,时间)表示。第 \(i\) 对二元组用两个整数 \(l_i, y_i\) 描述,分别表示选择的地点 \(l_i\) 和年份 \(y_i\)。

现在,他想计算出在这些时间和地点居住的生活质量。他定义居住的不方便指数为:在居住的年份,离居住点最远的商店类型到居住点的距离。类型 \(t\) 的商店到居住点的距离定义为:在指定的年份,类型 \(t\) 的所有营业的商店中,到居住点距离最近的一家到居住点的距离。我们说编号为 \(i\) 的商店在第 \(y\) 年在营业当且仅当 \(a_i \leq y \leq b_i\) 。注意,在某些年份中,可能在五福街上并非所有 \(k\) 种类型的商店都有至少一家在营业。在这种情况下,不方便指数定义为 \(−1\)。你的任务是帮助小明求出每对(坐标,时间)二元组居住的不方便指数。

解题思路 :

终于做贺完了2018的APIO纪念一下=w=

这个题好厉害啊,想了好久还是只会 \(nlog^3n\) ,于是就看了 kczno1的题解 ,然而还是细节好多。

考虑要使得区间中不同元素的个数等于元素种类数,容易想到通过记录每个位置的前驱将问题转化为数点。这样二分答案以后就可以通过求一个区间前驱 \(\min\) 来判断了,复杂度 \(O(nlog^2n)\)。

\(O(nlogn)\) 的做法点开链接就可以看到了,具体实现还要用一个multiset维护前驱,一个multiset维护每个叶子节点的极值,找到最远的出现第二次的元素后答案就是到左右两边的较短距离。

/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf ((int)(1e9))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int f = 0, ch = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
} const int N = 1000005;
multiset<int> s[N];
int Ans[N], d[N], pre[N], bef[N], len, cnt, tot, n, k, m; namespace Seg{
#define lson (u << 1)
#define rson (u << 1 | 1)
multiset<int> p[N]; int mn[N<<2];
inline void modify(int u, int l, int r, int pos, int x){
if(l == r){
if(x > 0) p[l].insert(x - 1);
else p[l].erase(p[l].find(-1 - x));
mn[u] = p[l].empty() ? inf : bef[*(p[l].begin())];
return;
}
int mid = l + r >> 1;
if(pos <= mid) modify(lson, l, mid, pos, x);
else modify(rson, mid + 1, r, pos, x);
mn[u] = min(mn[lson], mn[rson]);
}
inline int solve(int u, int l, int r, int x, int now){
if(l == r) return min(bef[l] - x, x - min(now, mn[u]));
int mid = l + r >> 1;
if(x > bef[mid])
return solve(rson, mid + 1, r, x, now);
int tmp = min(mn[rson], now);
if(tmp + bef[mid] + 1 <= 2 * x)
return solve(rson, mid + 1, r, x, now);
return solve(lson, l, mid, x, tmp);
}
inline void build(int u, int l, int r){
if(l == r){
p[l].insert(len+1);
if(l == len + 1)
for(int i = 1; i <= k; i++) p[l].insert(0);
mn[u] = bef[*(p[l].begin())];
return;
}
int mid = l + r >> 1;
build(lson, l, mid), build(rson, mid + 1, r);
mn[u] = min(mn[lson], mn[rson]);
}
} struct Node{ int op, t, x, y; } q[N];
inline bool cmp(const Node &A, const Node &B){
return (A.t == B.t) ? (A.op < B.op) : (A.t < B.t);
} inline void add(int pos, int x){
static multiset<int>::iterator it;
it = s[x].lower_bound(pos);
if(it != s[x].end()){
Seg::modify(1, 1, len + 1, *it, it == s[x].begin() ? -1 : (--it, -(*it++) - 1));
Seg::modify(1, 1, len + 1, *it, (pos + 1));
}
int tmp = (it == s[x].begin()) ? 1 : (*(--it) + 1);
Seg::modify(1, 1, len + 1, pos, tmp);
if(s[x].size() == 1) tot++;
s[x].insert(pos);
}
inline void del(int pos, int x){
static set<int>::iterator it;
it = s[x].lower_bound(pos);
if(it == s[x].begin()) Seg::modify(1, 1, len + 1, pos, -1);
else Seg::modify(1, 1, len + 1, pos, -(*(--it) + 1));
s[x].erase(s[x].find(pos));
it = s[x].lower_bound(pos);
if(it != s[x].end()){
Seg::modify(1, 1, len + 1, *it, -pos - 1);
Seg::modify(1, 1, len + 1, *it, it == s[x].begin() ? 1 : (--it, (*it++) + 1));
}
if(s[x].size() == 1) tot--;
} int main(){
read(n), read(k), read(m);
for(int i = 1, x, t, a, b; i <= n; i++){
read(x), read(t), read(a), read(b);
q[++cnt] = (Node){2, a, x, t};
q[++cnt] = (Node){1, b + 1, x, t};
d[++len] = x;
}
for(int i = 1, x, y; i <= m; i++){
read(x), read(y);
q[++cnt] = (Node){3, y, x, i};
d[++len] = x;
}
sort(d + 1, d + len + 1);
len = unique(d + 1, d + len + 1) - d - 1;
bef[len+1] = inf, bef[0] = -inf;
sort(q + 1, q + cnt + 1, cmp);
for(int i = 1; i <= cnt; i++){
int tmp = lower_bound(d + 1, d + len + 1, q[i].x) - d;
bef[tmp] = q[i].x, q[i].x = tmp;
}
Seg::build(1, 1, len + 1);
for(int i = 1; i <= k; i++) s[i].insert(len+1);
for(int i = 1; i <= cnt; i++){
if(q[i].op == 2) add(q[i].x, q[i].y);
if(q[i].op == 1) del(q[i].x, q[i].y);
if(q[i].op == 3){
if(tot < k) Ans[q[i].y] = -1;
else Ans[q[i].y] = Seg::solve(1, 1, len + 1, bef[q[i].x], inf);
}
}
for(int i = 1; i <= m; i++) printf("%d\n", Ans[i]);
return 0;
}

「APIO2018新家」的更多相关文章

  1. 「APIO2018选圆圈」

    「APIO2018选圆圈」 题目描述 在平面上,有 \(n\) 个圆,记为 \(c_1, c_2, \ldots, c_n\) .我们尝试对这些圆运行这个算法: 找到这些圆中半径最大的.如果有多个半径 ...

  2. 「萌新指南」SOA vs. 微服务:What’s the Difference?

    实话实说,在我还没有实习之前,我是连 SOA 是啥都不知道的,只听说过微服务,毕竟微服务实在太火了,想不知道都难,我觉得实习的时候肯定也是微服务,进组之后发现是 SOA 架构,当时都懵了,看了很多文档 ...

  3. LOJ.2585.[APIO2018]新家(二分 线段树 堆)

    LOJ 洛谷 UOJ BZOJ 四OJ Rank1 hhhha 表示这个b我能装一年→_→ 首先考虑离线,将询问按时间排序.对于每个在\([l,r]\)出现的颜色,拆成在\(l\)加入和\(r+1\) ...

  4. [loj2585][APIO2018]新家

    题目 一条街上有\(n\) 个点,坐标为\(x_i\) , 店的种类为\(t_i\) , 开业时间为 \([a_i,b_i]\) ; 定义一种类型到一个点的距离为这种类的点到这个点的最近距离 ; 定义 ...

  5. BZOJ5462 APIO2018新家(线段树+堆)

    一个显然的做法是二分答案后转化为查询区间颜色数,可持久化线段树记录每个位置上一个同色位置,离线后set+树状数组套线段树维护.这样是三个log的. 注意到我们要知道的其实只是是否所有颜色都在该区间出现 ...

  6. [BZOJ5462][APIO2018]新家(线段树+堆)

    其实这个题第一反应一定是线段树分治,但是这样反而更难考虑了(实际上是可做的但很难想到),可见即使看上去最贴切的算法也未必能有效果. 考虑这个DS题,没有什么模型的转化,可能用到的无非就是线段树.平衡树 ...

  7. LOJ #2585. 「APIO2018」新家

    #2585. 「APIO2018」新家 https://loj.ac/problem/2585 分析: 线段树+二分. 首先看怎样数颜色,正常的时候,离线扫一遍右端点,每次只记录最右边的点,然后查询左 ...

  8. 「JLOI2014」松鼠的新家

    「JLOI2014」松鼠的新家 传送门 两种做法: 树上差分 \(O(n)\) 树链剖分 \(O(nlogn)\) 树剖比较好写而且无脑,树上差分复杂度优秀一些但是会有点难调. 这里给出树剖写法: 唯 ...

  9. 未来科技城 x 奇点云打造「企业数据大脑」,助力1.3万家企业服务

    “当前,政府数字化和数字政府建设已成为一种趋势.一种必然,并且有了一条水到渠成式的实现路径.” 上升为国家战略的数字中国建设加速了”智慧政务“的生动实践,杭州未来科技城的「企业数据大脑」就是一个典型. ...

随机推荐

  1. AngularJs 文件上传(实现Multipart/form-data 文件的上传)

    <!-- 上传yml文件 --> <div class="blackBoard" ng-show="vm.showUpop==true"> ...

  2. Term Term ssh登陆linux后 显示乱码

    setup----terminal----locale----“chinese” OK!!!!!

  3. u-boot启动第二阶段以及界面命令分析

    u-boot第一阶段完成了一些平台相关的硬件的配置,第一阶段所做的事情也是为第二阶段的准备,我们知道在第一阶段最后时搭建好C运行环境,之后调用了start_armboot(),那么很显然第二阶段从st ...

  4. swiper (Table切换和动态加载时候出现的问题)

    本文为让心灵-去旅行原创,转载请说明.. 我们在写一个简单的swiper图片轮播的时候很简单,是写死的也就那么几张图片轮播.如果这时候图片和一些东西是后台的,你从js里动态添加到DOM时,这时候你就会 ...

  5. vue数据传递--我有特殊的实现技巧

    最近碰到了比较多的关于vue的eventBus的问题,之前定技术选型的时候也被问到了,vuex和eventBus的使用范围.所以简单的写一下.同时有一种特殊的实现方案. 有这么几种数据传递方式,vue ...

  6. C++面试总结

    1.多态       C++多态分两种--静态和动态,其中静态联编支持的多态称为编译时多态,包括重载和模板:动态联编支持的多态称为运行时多态,包括 继承和虚函数实现. 多态主要是由虚函数实现的,虚函数 ...

  7. 关于OnPaint、FormPaint会不停的触发 触发多次的情形---讨论总结

    关于OnPaint会不停的一直触发 触发多次的问题,是这样的 首先OnPaint是响应windows的WM_PAINT消息的,你显示器上 能看到的比如说 按钮button, memo什么的 都是画出来 ...

  8. Codeforces 798D - Mike and distribution(二维贪心、(玄学)随机排列)

    题目链接:http://codeforces.com/problemset/problem/798/D 题目大意:从长度为n的序列A和序列B中分别选出k个下表相同的数要求,设这两个序列中k个数和分别为 ...

  9. Python股票信息抓取(二)

    在一的基础上,想着把所有的折线图放在一个图中,然后图的结果如图所示: 不是略丑,是很丑~ 依然的单进程,只是将图标结果放在了一张图里 代码如下: #-*-coding:utf-8 -*- import ...

  10. objective-c Quick Reference