「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. 用Matlab实现字符串分割(split)

    用Matlab实现字符串分割(split)Posted on 2011/08/08 Matlab的字符串处理没有C#强大,本身又没有提供OO特性,需要依赖别的手段完成这项任务. 我们在这里借助正则表达 ...

  2. HDU 2044 Coins

    有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行.请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数. 其中,蜂房的结构如下所示.   Input输入数据的第一行是一个整数N,表示测试实例的个数,然 ...

  3. hdu 3729 I'm Telling the Truth(二分匹配_ 匈牙利算法)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3729 I'm Telling the Truth Time Limit: 2000/1000 MS ( ...

  4. 多维数组的字符依次输出,用python实现

    #-*- coding=utf-8 -*-listm=["s","l","z","x","l",&q ...

  5. webgote的例子 数据库与sql注入的相关联系(1)

    大家好我是时光凉春衫薄 之前将讲的sql注入有点随便了我同事也觉得有些地方看不懂,往后的几天我尽量写的细一点.尽可能让大家能看懂.(新手出道大佬多多指教.欢迎评论批评.) 数据库与sql注入的相关联系 ...

  6. 21.Merge Two Sorted Lists---《剑指offer》面试17

    题目链接:https://leetcode.com/problems/merge-two-sorted-lists/description/ 题目大意: 给出两个升序链表,将它们归并成一个链表,若有重 ...

  7. SPOJ DQUERY D-query (在线主席树/ 离线树状数组)

    版权声明:本文为博主原创文章,未经博主允许不得转载. SPOJ DQUERY 题意: 给出一串数,询问[L,R]区间中有多少个不同的数 . 解法: 关键是查询到某个右端点时,使其左边出现过的数都记录在 ...

  8. 26_Python的内置函数

    The Python interpreter has a number of functions and types built into it that are always available.P ...

  9. Freemaker如何遍历key为non-string类型的map?

    (一) 前置知识 Freemaker默认配置下会使用SimpleHash去包装后台传递的hashmap,下段摘抄自官方reference 同样,当你传递进去一个hashmap实例时,会替换为一个sim ...

  10. Qt跨线程调用错误解析及解决办法

    错误提示:Error: Cannot create children for a parent that is in a different thread. 错误案例分析 新建SerialLink子线 ...