做题arc068_e-Snuke Line——利用特殊性质分讨

Posted cly_none

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了做题arc068_e-Snuke Line——利用特殊性质分讨相关的知识,希望对你有一定的参考价值。

显然,对于所有跨度暴力扫一遍的复杂度本身只有\(O(n \log n)\)
容易想到在每一个到达的位置加上覆盖这个位置的区间数。剩下的问题就在于如何处理覆盖了多个位置的区间。
记录已访问或去重都是难以实现的。但注意到一个性质:

所有长度不小于跨度的区间一定都能被访问到,所有长度小雨跨度的区间至多访问一次。

于是我们枚举跨度,维护长度不小于当前跨度的区间数,把长度小于当前跨度的区间加入到一个支持区间加和单点查询的数据结构里就可以了。
时间复杂度\(O(n \log ^2 n)\)

#include <bits/stdc++.h>
using namespace std;
const int N = 300010, M = 100010;
#define lowbit(x) ((x) & (-(x)))
int v[M],n,m,s,ans,p=1;
struct data {
  int l,r;
  bool operator < (const data& x) const {
    return r - l < x.r - x.l;
  }
} dat[N];
void add(int p,int val) {
  for (; p <= s ; p += lowbit(p))
    v[p] += val;
}
int query(int p) {
  int res = 0;
  for (; p ; p -= lowbit(p))
    res += v[p];
  return res;
}
int main() {
  scanf("%d%d",&n,&m);
  for (int i = 1 ; i <= n ; ++ i)
    scanf("%d%d",&dat[i].l,&dat[i].r);
  sort(dat+1,dat+n+1);
  s = m+1;
  for (int i = 1 ; i <= m ; ++ i) {
    while (dat[p].r - dat[p].l + 1 < i && p <= n) {
      add(dat[p].l+1,1);
      add(dat[p].r+2,-1);
      p ++;
    }
    ans = n - p + 1;
    for (int j = 0 ; j <= m ; j += i)
      ans += query(j+1);
    printf("%d\n",ans);
  }
  return 0;
}



小结:利用题目特殊性质分类讨论可以有效简化题目。

以上是关于做题arc068_e-Snuke Line——利用特殊性质分讨的主要内容,如果未能解决你的问题,请参考以下文章

arc068ESnuke Line

ARC068E Snuke Line

arc068 E: Snuke Line

[Arc068D/At2299] Card Eater - 结论

ARC068FSolitaire 前缀和优化dp

arc068FSolitaire