zoukankan      html  css  js  c++  java
  • 【做题】CERC2017B. Buffalo Barricades——时间倒流

    原文链接 https://www.cnblogs.com/cly-none/p/CERC2017B.html

    题意:在一个网格平面上,有(n)个点,其中第(i)个点在以((x_i, y_i))为右上角的网格中。有(m)次操作,每次给出一个点((x,y)),表示从((x,y))开始,向左和向下画线直到与之前画的线或坐标轴相交。这样会划分出以((x,y))为右上角的新区域。你需要对每次操作求出,新区域中点的数量。

    $n , m leq 3 imes 10^5, 1 leq x_i, y_i leq 10^9, $ 每次操作的 (x)(y) 分别互不相同。

    首先,我们容易得出各种(O(n log ^ 2n))的数据结构做法。然而,它们并没有太大的启发意义。

    考虑离线下来,处理每个点对所有操作的贡献。

    考虑求出每个点和操作最后是被哪个操作控制的。也就是能直接覆盖这个点(或操作)的操作中时间最早的。这样会形成森林的结构。显然,一个点只会对它的祖先产生贡献。而它对某个祖先(v)产生贡献的冲要条件就是在它到(v)的路径上没有比(v)更早的操作。

    求这个森林可以使用扫描线。按(y)从上往下扫描,每加入一个操作就删去在它前面的出现时间晚于它的操作。这可以用set来维护。

    剩下的部分可以按时间从前往后枚举所有操作,每次答案就是它的子树和,然后切断它与父亲的边。方便起见,可以用时间倒流的技巧,就相当与每次合并一个点和它的父亲。用并查集维护即可。

    时间复杂度(O(n log n))

    #include <bits/stdc++.h>
    using namespace std;
    #define gc() getchar()
    template <typename tp>
    inline void read(tp& x) {
      x = 0; char tmp; bool key = 0;
      for (tmp = gc() ; !isdigit(tmp) ; tmp = gc())
        key = (tmp == '-');
      for ( ; isdigit(tmp) ; tmp = gc())
        x = (x << 3) + (x << 1) + (tmp ^ '0');
      if (key) x = -x;
    }
    const int N = 300010, INF = 0x3f3f3f3f;
    struct edge {
      int la,b;
    } con[N << 1];
    int tot,fir[N << 1];
    void add(int from,int to) {
      con[++tot] = (edge) {fir[from],to};
      fir[from] = tot;
    }
    struct data {
      int x,y,v;
      bool operator < (const data& a) const {
        return y > a.y;
      }
    } dat[N << 1];
    int n,m,cnt,fa[N],val[N],uni[N],ans[N];
    int getfa(int pos) {
      return pos == uni[pos] ? pos : uni[pos] = getfa(uni[pos]);
    }
    typedef pair<int,int> pii;
    set<pii> st;
    set<pii> :: iterator t, t1;
    void ins(int x,int y) {
      t = st.insert(pii(x,y)).first;
      while (t != st.begin()) {
        t1 = t;
        -- t1;
        if (t1 -> second < y) break;
        st.erase(t1);
      }
    }
    int ask(int p) {
      return st.upper_bound(pii(p+1,0))->second;
    }
    int main() {
      read(n);
      for (int i = 1, x, y ; i <= n ; ++ i) {
        read(x), read(y);
        -- x, -- y;
        dat[++cnt] = (data) {x,y,0};
      }
      read(m);
      for (int i = 1, x, y ; i <= m ; ++ i) {
        read(x), read(y);
        dat[++cnt] = (data) {x,y,i};
      }
      dat[++cnt] = (data) {INF,INF,m+1};
      sort(dat+1,dat+cnt+1);
      for (int i = 1, las = 1, tmp ; i <= cnt ; ++ i) {
        if (dat[i].y != dat[las].y) {
          for (int j = las ; j < i ; ++ j)
    				if (dat[j].v) ins(dat[j].x, dat[j].v);
          las = i;
        }
        tmp = ask(dat[i].x);
        if (dat[i].v) fa[dat[i].v] = tmp;
        else ++ val[tmp];
      }
      for (int i = 1 ; i <= m ; ++ i)
        uni[i] = i;
      for (int i = m ; i >= 1 ; -- i) {
        ans[i] = val[getfa(i)];
        uni[getfa(i)] = getfa(fa[i]);
        val[getfa(fa[i])] += ans[i];
      }
      for (int i = 1 ; i <= m ; ++ i)
        printf("%d
    ",ans[i]);
      return 0;
    }
    

    小结:这是一道技巧性比较强的数据结构题。利用询问间的关系解题的思路,还是有启发意义的。

  • 相关阅读:
    Resource interpreted as Stylesheet but transferred with MIME type application/x-css
    scrapy 的settings.py中设置自定义属性
    scrapy下载图片到指定路径
    scrapy 自动下载图片
    Python处理json的错误 obj, end = self.scan_once(s, idx) ValueError: Expecting property name: line 2 column 17 (char 18)
    [ZJOI2012]数列 题解 [高精]
    [ZJOI2020]传统艺能 题解 [DP+矩阵+分类讨论]
    《终将成为你》简评
    GJGHFD的关键点 题解 [倍增+线段树+贪心]
    GJGHFD的排列 题解 [DP]
  • 原文地址:https://www.cnblogs.com/cly-none/p/CERC2017B.html
Copyright © 2011-2022 走看看