• 「APIO2018新家」


    「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
    ", Ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    我与酷派手机N900+的艰难之旅
    从ASPNET1.1迁移到了ASPNET2.0遇到ORA01000: 超出打开游标的最大数
    彩铃平台接口独立取得阶段性胜利
    中央音乐平台的MD5算法问题
    彩铃接口独立完毕
    'OraOLEDB.Oracle.1' provider is not registered on the local machine.错误的解决
    程序员的陷阱
    ASP NET页面下载程序
    从aspnet1.1升级到aspnet2.0的小问题
    彩铃平台接口的计费服务问题解决
  • 原文地址:https://www.cnblogs.com/mangoyang/p/10152304.html
Copyright © 2020-2023  润新知