LOJ #2585. 「APIO2018」新家

#2585. 「APIO2018」新家

https://loj.ac/problem/2585

分析:

  线段树+二分。

  首先看怎样数颜色,正常的时候,离线扫一遍右端点,每次只记录最右边的点,然后查询左端点,这里不太行。这里只需要统计是否全出现过,pre[i]为这个颜色的上一个位置,那么这也就说明了pre[i]+1这段区间没出现过,所以要求[r+1,n]这段区间的最小的pre都要大于等于l。于是这就是线段树区间查询最小值了。

  注意的是,每个点的pre有多个,每个叶子节点包含一个set,把所有的值插入进去,取最小值。用两个堆维护也可以,(取最小值,删除一个值)。

  然后就可以二分一个长度,然后查询[x-len,x+len]这段区间是否都有所有的颜色就行了。复杂度$O(nlog^2n)$

  一个log的做法,二分的过程放到了线段树上。  

代码:

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<cmath>
  6 #include<cctype>
  7 #include<set>
  8 #include<queue>
  9 #include<vector>
 10 #include<map>
 11 using namespace std;
 12 typedef long long LL;
 13 
 14 inline int read() {
 15     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
 16     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
 17 }
 18 
 19 const int N = 300005;
 20 const int INF = 1e9;
 21 
 22 struct Node{
 23     int opt, x, col, t;
 24     Node() {}
 25     Node(int a,int b,int c,int d) { opt = a, x = b, col = c, t = d; }
 26     bool operator < (const Node &A) const {
 27         return t == A.t ? opt > A.opt : t < A.t; // 如果时间相同,先加入,在询问,再删除 
 28     }
 29 }A[N * 3];
 30 struct Heap{
 31     priority_queue<int, vector<int>, greater<int> > q1, q2;
 32     int size() { return q1.size() - q2.size(); }
 33     void add(int x) { q1.push(x); }
 34     void del(int x) { q2.push(x); }
 35     int top() {
 36         while (!q2.empty() && q1.top() == q2.top()) q1.pop(), q2.pop();
 37         return q1.top();
 38     }
 39 //    multiset<int> s;
 40 //    int size() { return s.size(); }
 41 //    void add(int x) { s.insert(x); }
 42 //    void del(int x) { s.erase(s.find(x)); }
 43 //    int top() { return *s.begin(); }
 44 }H[N];
 45 multiset<int> S[N];
 46 int ans[N], Id[N * 30], ls[N * 30], rs[N * 30], Mn[N * 30];
 47 int n, k, m, Index_Heap, Index_Tree, Root, Now_Col;
 48 
 49 void update(int l,int r,int &rt,int p,int u,int v) {
 50     if (!rt) rt = ++Index_Tree;
 51     if (l == r) {
 52         if (!Id[rt]) Id[rt] = ++Index_Heap;
 53         Heap &now = H[Id[rt]];
 54         if (u) now.add(u);
 55         if (v) now.del(v);
 56         Mn[rt] = now.size() ? now.top() : INF;
 57         return ;
 58     }
 59     int mid = (l + r) >> 1;
 60     if (p <= mid) update(l, mid, ls[rt], p, u, v);
 61     else update(mid + 1, r, rs[rt], p, u, v);
 62     Mn[rt] = min(Mn[ls[rt]], Mn[rs[rt]]);
 63 }
 64 void add(const Node &now) {
 65     multiset<int> &s = S[now.col];
 66     multiset<int> :: iterator r = s.upper_bound(now.x), l = r; l--;
 67     update(0, INF, Root, *r, now.x, *l);
 68     update(0, INF, Root, now.x, *l, 0);
 69     if (s.size() == 2) Now_Col ++;
 70     s.insert(now.x);
 71 }
 72 void del(const Node &now) {
 73     multiset<int> &s = S[now.col];
 74     s.erase(s.find(now.x));
 75     if (s.size() == 2) Now_Col --;
 76     multiset<int> :: iterator r = s.upper_bound(now.x), l = r; l--;
 77     update(0, INF, Root, *r, *l, now.x);
 78     update(0, INF, Root, now.x, 0, *l);
 79 }
 80 int Ask(int p) {
 81     if (Now_Col != k) return -1;
 82     int l = 0, r = INF, now = Root, ans = INF;
 83     while (l != r) { // 模拟在线段树上走的过程 
 84         int mid = (l + r) >> 1, tmp = min(ans, Mn[rs[now]]); 
 85         if (p <= mid && tmp + mid >= p + p) ans = tmp, r = mid, now = ls[now];
 86         else l = mid + 1, now = rs[now];
 87     }
 88     return l - p;
 89 }
 90 int main() { 
 91     n = read(), k = read(), m = read();
 92     Mn[0] = INF;
 93     for (int i = 1; i <= k; ++i) // 初始往INF处加入k个-INF 
 94         S[i].insert(-INF), S[i].insert(INF), update(0, INF, Root, INF, -INF, 0); 
 95     int tot = 0;
 96     for (int i = 1; i <= n; ++i) {
 97         int x = read(), t = read(), a = read(), b = read();
 98         A[++tot] = Node(1, x, t, a); A[++tot] = Node(-1, x, t, b);
 99     }
100     for (int i = 1; i <= m; ++i) {
101         int x = read(), t = read();
102         A[++tot] = Node(0, x, i, t);
103     }
104     sort(A + 1, A + tot + 1);
105     for (int i = 1; i <= tot; ++i) {
106         if (A[i].opt == 1) add(A[i]);
107         else if (A[i].opt == -1) del(A[i]);
108         else ans[A[i].col] = Ask(A[i].x);
109     }
110     for (int i = 1; i <= m; ++i) printf("%d
",ans[i]);
111     return 0;
112 }
原文地址:https://www.cnblogs.com/mjtcn/p/10063513.html