Atcoder abc324

https://atcoder.jp/contests/abc324

G -  Generate Arrays

给定一个 1~n的排列p

S[0] = p

q个操作

  • 1类,选定S[s_i]把 idx>= x_i的删除
  • 2类,选定S[s_i]中 所有 值 > v_i的删除
  • 操作后 让S[i]=删除的原顺序的序列,并输出S[i]的长度

n 2e5

q 2e5

6s

1024mb

我的思路

二维平面点 (i,p[i]) 然后 每个序列对应一个矩形

每个操作对应一次矩形分割

vector<map>的fenwick

但是 似乎多写了一层二分,多了log 导致acx36,tle x25

我这个似乎是$Q(\log N)^3+N(\log N)^2$

题解

反向合并技术

如果倒着看,合并两个长度$a,b$的序列,$O(1+\min(a,b)\log\min(a,b))$

// 也就是拆分的时候时间复杂度为 拆分后两个中短的那个

总复杂度为$O(Q+N(\log N)^2)$

考虑基于$std::set$ (平衡二叉树)来管理$(i,a_i)$和$(a_i,i)$


所以, 实现逻辑就是

每次 操作判断操作的多还是剩下的多来决定实际操作的是少的部分

而实际操作的内容,是通过for 元素 + 每次$O(\log N)$的操作


啊?好有道理!

核心的原理 和 做启发式合并 小的向大的合并的有点像,这是每次拆,都是拆小的那一半,所以第一次最多能操作n/2的,第2+3次最多操作n/2,第4+5+6+7次最多操作n/2,每个单元素是O(log N)操作

总结

G:

啊 不是 洛谷一堆人用神奇高级数据结构 单log过题了????

然后学了一下

std::set.emplace_hint,可以指定位置的插入set减少插入后排序的消耗

noexcept 保证不抛出异常

std::size

1
2
templateclass C >  
constexpr auto sizeconst C& c ) -> decltype(c.size()); // since C++17

啊 这个官方题解的想法 回过头来看竟然如此简单,又很有道理!!??