zoukankan      html  css  js  c++  java
  • 【APIO2018】新家

    题目链接

    【APIO2018】新家

    做法

    对于这种区间修改、单点询问的题目,可以将询问离线再扫描线。
    考虑对于一个答案 $ ans_i $ 合法,当且仅当 $ (l_i + ans_i, INF) $ 中每种店上一次出现的位置不小于 $ l_i + ans_i $ 。对于每种店都开一个 multiset 即可维护前驱。
    这样每一次加入/删除会需要区间修改前驱,代码难度大,考虑 $ (l_i + ans_i, INF) $ 中每种店上一次出现的位置不小于 $ l_i + ans_i $ 的另一种解释,即 $ (l_i + ans_i, INF) $ 每个位置中每种店每个位置上一次出现的位置最小值不小于 $ l_i + ans_i $ ,然后就可以单点修改了。用线段树维护前驱最小值。
    询问可以二分答案,更优秀的做法是在线段树上二分。

    #include <bits/stdc++.h>
    #define pb push_back
    using namespace std;
    typedef multiset<int>::iterator IT;
    const int N = 600010, LG = 20, INF = 1000000000;
    int n, k, m, ans[N], clr;
    struct Q {
    	int opt, pos, type, pri;
    	Q(int Opt = 0, int Pos = 0, int Type = 0, int Pri = 0) :
    		opt(Opt), pos(Pos), type(Type), pri(Pri) {}
    	inline bool operator<(const Q &yy)const {
    		return pri == yy.pri ? opt < yy.opt : pri < yy.pri;
    	}
    }; Q q[N + N]; int len;
    
    multiset<int> pp[N], st[N * LG];
    int rt, tot, cnt, lf[N * LG], rf[N * LG], mn[N * LG], id[N * LG];
    
    inline int Max(const int &x, const int &y) { return x > y ? x : y; }
    inline int Min(const int &x, const int &y) { return x < y ? x : y; }
    void mdy(int &u, int l, int r, int x, int ad, int dl) {
    	if(!u) u = ++tot;
    	if(l >= r) {
    		if(!id[u]) id[u] = ++cnt;
    		multiset<int> &s = st[id[u]];
    		if(ad) s.insert(ad);
    		if(dl) s.erase(s.find(dl));
    		mn[u] = s.size() ? *s.begin() : INF; return ;
    	}
    	int mid = (l + r) >> 1;
    	if(x <= mid) mdy(lf[u], l, mid, x, ad, dl);
    	else mdy(rf[u], mid + 1, r, x, ad, dl);
    	mn[u] = Min(mn[lf[u]], mn[rf[u]]);
    }
    void add(Q x) {
    	multiset<int> &s = pp[x.type];
    	IT itr = s.upper_bound(x.pos), itl = itr; --itl;
    	mdy(rt, 0, INF, *itr, x.pos, *itl), mdy(rt, 0, INF, x.pos, *itl, 0);
    	s.insert(x.pos); if(s.size() == 3) ++clr;
    }
    void del(Q x) {
    	multiset<int> &s = pp[x.type]; s.erase(s.find(x.pos));
    	IT itr = s.upper_bound(x.pos), itl = itr; --itl;
    	mdy(rt, 0, INF, *itr, *itl, x.pos), mdy(rt, 0, INF, x.pos, 0, *itl);
    	if(s.size() == 2) --clr;
    }
    int ask(Q x) {
    	if(clr < k) return -1;
    	int l = 0, r = INF, mid, t, tt = INF, u = rt;
    	for(; l < r;) {
    		mid = (l + r) >> 1, t = Min(tt, mn[rf[u]]);
    		if(x.pos <= mid && t + mid >= x.pos * 2)
    			tt = t, r = mid, u = lf[u];
    		else u = rf[u], l = mid + 1;
    	}
    	return l - x.pos;
    }
    int main() {
    	scanf("%d%d%d", &n, &k, &m), mn[0] = INF;
    	for(int i = 1; i <= k; i++)
    		pp[i].insert(-INF), pp[i].insert(INF), mdy(rt, 0, INF, INF, -INF, 0);
    	for(int i = 1, x, t, a, b; i <= n; i++) {
    		scanf("%d%d%d%d", &x, &t, &a, &b);
    		q[++len] = Q(1, x, t, a), q[++len] = Q(2, x, t, b + 1);
    	}
    	for(int i = 1, x, y; i <= m; i++)
    		scanf("%d%d", &x, &y), q[++len] = Q(3, x, i, y);
    	sort(q + 1, q + len + 1);
    	for(int i = 1; i <= len; i++) {
    		if(q[i].opt == 1) add(q[i]);
    		else if(q[i].opt == 2) del(q[i]);
    		else ans[q[i].type] = ask(q[i]);
    	}
    	for(int i = 1; i <= m; i++) printf("%d
    ", ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    Selenium环境搭建
    系统测试用例评审checklist
    软件测试入门
    App测试方法总结
    好东西并查集
    自己编写一个数组去掉重复元素的函数
    杭电OJ BestCoder28期1001Missing number问题(小技巧偏移法)
    介绍一个二次排序的小技巧(best coder27期1001jump jump jump)
    ntohs的一个简单实现(将网络流中用两个字节16进制表示的资源数(如DNS)和长度转换为整形)
    一个节省空间的小技巧
  • 原文地址:https://www.cnblogs.com/daniel14311531/p/10904742.html
Copyright © 2011-2022 走看看