• 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 }
  • 相关阅读:
    【洛谷P3374】【模板】树状数组 1
    【vijos1460】拉力赛
    NOIp2013货车运输
    【codevs1519】过路费
    【codevs1036】商务旅行
    【codevs2370】小机房的树
    【洛谷P3398】仓鼠找sugar
    【洛谷P2912】[USACO08OCT]牧场散步Pasture Walking
    sql语句绑定方法
    单实例asm,修改主机名和ip地址后的重配置+集群重新配置GI
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10063513.html
Copyright © 2020-2023  润新知