LOJ bitset+分块 大内存毒瘤题

题面

LOJ bitset+分块 大内存毒瘤题_第1张图片

LOJ bitset+分块 大内存毒瘤题_第2张图片



$ solution: $

真的没有想到可以用分块。

但是可以发现一个性质,每个询问只关心这个点最后一次赋值操作,和这个赋值操作后的所有取 $ min $ 操作。这个感觉很有用,但是真的很难让人想到低于 $ n\times m $ 的做法。基于 $ DAG $ 的数据结构是目前很少需要掌握的(好吧我都不知道有什么数据结构可以维护 $ DAG $ )所以肯定得骚操作。

我们可以发现一个 $ DAG $ 的性质,如果有一连串赋值操作我们可以根据拓扑序 $ O(n) $ 将所有操作完成,直接按顺序从后往前赋值,这样每个点赋值之后就不会再被访问。同理的, 如果有一连串取 $ min $ 操作我们也可以根据拓扑序 $ O(n) $ 将所有操作完成,直接 $ min $ 值从小到大取 $ min $, 这样每个点在取 $ min $ 之后就不会再被访问。但是当我们将这两种操作合到一起时就不行了。

但是联想一下上面说的性质:每个询问只关心这个点最后一次赋值操作,和这个赋值操作后的所有取 $ min $ 操作。我们可以搞出一个分块来,先预处理2操作,将2操作序列分块,并将每一块用上面的方法统计出每个结点在每个块内的取 $ min $ 后的值(初值inf)。然后我们就可以 $ \sqrt{n} $ 的求出任意一个区间里某个节点取 $ min $ 的最小值(其实还需要一个操作)。然后我们只需要快速找到每个询问的节点的最后一次赋值操作的编号,即赋值的大小,就可以得到答案。找到这个编号,我们可以对1操作分块来完成。

但是上述操作我们还需要知道一个东西,因为分块两边的小区间是要暴力遍历的,这个我们需要知道每个操作能否对某个点产生影响,这个等同于我们要知道 $ DAG $ 中一个点能否到另一个点。这个很奇妙的我们可以用 $ bitset $ 暴力完成。因为这个是无法用低于 $ n\times m $ 的复杂度完成,但是只涉及能否我们可以用二进制

  1. 仔细分析求得答案需要什么关键信息
  2. 对于一连串操作可以一次完成,就考虑分治或分块
  3. 对于两种操作会互相影响,考虑先预处理一种操作在进行第二种操作
  4. 二进制和是与否,这个对于复杂度优化很好用。
  5. $ DAG $ 中的一些问题是难以用低于 $ n\times m $ 的做法完成的!

LOJ bitset+分块 大内存毒瘤题_第3张图片



$ code: $

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define ll long long
#define db double
#define rg register int

using namespace std;

int tt,t=1;
int n,m,q,ff;
int a[100005];
int idx[100005];
int fq[100005];
int fm[100005][404];
int vis[100005];
bitset<100005> f[100005];

struct su{
    int to,next;
}b[200005];
int tou[100005];

struct pi{
    int id,x,v,op;
    inline bool operator <(const pi &i)const{
        return v

你可能感兴趣的:(LOJ bitset+分块 大内存毒瘤题)