\(\mathscr{Description}\)

  Link. (It's empty temporarily.)

  给定排列 \(\{a_n\}\),\(q\) 次询问,每次给出 \([l,r]\),求升序枚举 \(a_{l..r}\) 时下标的移动距离。

  \(n,q\le5\times10^5\)。

\(\mathscr{Solution}\)

  我写了个不加莫队,它慢死了。

  我写了个 Ynoi 风格的纯纯分块预处理,它慢死了。

  我写了个 polylog 的正解,它还是慢死了。


  喵树分治,每次处理跨过区间中点的询问。左右区间互相的影响形式形如:“若右区间包含一个 \([x,y]\) 内的数,则答案变化量为 \(\Delta\)。”注意左右区间包含了哪些数仅跟一个端点有关,所以类似于区间数点的形式,可以考虑离线维护。

  以计算左区间产生的 \(\Delta\) 为例。枚举左区间端点 \(p=\textit{mid}..l\),用 std::set 之类的东西暴力维护左区间前驱后继。现在加入 \(a_p\),设其前驱为 \(x\),后继为 \(y\),内部贡献先计算;对于跨区间影响,我们得到了两个新的“连续键” \(x\rightarrow a_p\) 以及 \(a_p\rightarrow y\),去掉了一个旧的“连续键” \(x\rightarrow y\),而我们可以分别找到右区间第一个能“断键”的数的位置 \(k\),把对应的变化量挂在 \(k\) 位置。然后枚举左端点为 \(p\) 的询问,将询问对应的右端点及其左侧的所有“断键”变化量都计入询问答案。右区间也做类似的事情即可。

  复杂度是 \(\mathcal O(n\log^2 n)\),隐约记得 lxl 说有基于并查集的低于这一复杂度的做法?

\(\mathscr{Code}\)

  那个线段树可以替换成离线啊,怪不得那么慢 qwq。

/*+Rainybunny+*/

#include <bits/stdc++.h>

#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i) typedef long long LL;
typedef std::pair<int, int> PII;
#define fi first
#define se second inline char fgc() {
static char buf[1 << 17], *p = buf, *q = buf;
return p == q && (q = buf + fread(p = buf, 1, 1 << 17, stdin), p == q) ?
EOF : *p++;
} template <typename Tp = int>
inline Tp rint() {
Tp x = 0, s = fgc(), f = 1;
for (; s < '0' || '9' < s; s = fgc()) f = s == '-' ? -f : f;
for (; '0' <= s && s <= '9'; s = fgc()) x = x * 10 + (s ^ '0');
return x * f;
} template <typename Tp>
inline void wint(Tp x) {
if (x < 0) putchar('-'), x = -x;
if (9 < x) wint(x / 10);
putchar(x % 10 ^ '0');
} inline int iabs(const int u) { return u < 0 ? -u : u; }
template <typename Tp>
inline void chkmin(Tp& u, const Tp& v) { v < u && (u = v, 0); }
template <typename Tp>
inline void chkmax(Tp& u, const Tp& v) { u < v && (u = v, 0); }
template <typename Tp>
inline Tp imin(const Tp& u, const Tp& v) { return u < v ? u : v; }
template <typename Tp>
inline Tp imax(const Tp& u, const Tp& v) { return u < v ? v : u; } const int MAXN = 5e5, IINF = 0x3f3f3f3f;
int n, q, a[MAXN + 5], ref[MAXN + 5];
LL ans[MAXN + 5];
struct Query { int l, r, id; };
std::vector<Query> ask[MAXN * 2 + 5]; struct SegmentTree {
int mn[MAXN << 2], mx[MAXN << 2]; inline void build(const int u, const int l, const int r) {
mn[u] = IINF, mx[u] = -1;
if (l == r) return ;
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
} inline void modify(const int u, const int l, const int r,
const int x, const int v) {
if (l == r) {
if (v) mn[u] = mx[u] = v;
else mn[u] = IINF, mx[u] = -1;
return ;
}
int mid = l + r >> 1;
if (x <= mid) modify(u << 1, l, mid, x, v);
else modify(u << 1 | 1, mid + 1, r, x, v);
mn[u] = imin(mn[u << 1], mn[u << 1 | 1]);
mx[u] = imax(mx[u << 1], mx[u << 1 | 1]);
} inline int qmin(const int u, const int l, const int r,
const int ql, const int qr) {
if (ql <= l && r <= qr) return mn[u];
int mid = l + r >> 1, ret = IINF;
if (ql <= mid) chkmin(ret, qmin(u << 1, l, mid, ql, qr));
if (mid < qr) chkmin(ret, qmin(u << 1 | 1, mid + 1, r, ql, qr));
return ret;
} inline int qmax(const int u, const int l, const int r,
const int ql, const int qr) {
if (ql <= l && r <= qr) return mx[u];
int mid = l + r >> 1, ret = -1;
if (ql <= mid) chkmax(ret, qmax(u << 1, l, mid, ql, qr));
if (mid < qr) chkmax(ret, qmax(u << 1 | 1, mid + 1, r, ql, qr));
return ret;
}
} sgt; struct BIT {
LL val[MAXN + 5];
bool rec[MAXN + 5]; int stk[MAXN + 5]; inline void add(int x, const int v) {
for (; x <= n; x += x & -x) {
val[x] += v, !rec[x] && (rec[stk[++stk[0]] = x] = true);
}
} inline LL sum(int x) {
LL ret = 0;
for (; x; x -= x & -x) ret += val[x];
return ret;
} inline void restore() {
for (int& top = stk[0]; top; --top) {
rec[stk[top]] = false, val[stk[top]] = 0;
}
}
} bit; #define TID(l, r) (l + r | (l != r)) inline void hang(const int l, const int r, const Query& qr) {
int mid = l + r >> 1;
if (qr.l <= mid && mid < qr.r) return ask[TID(l, r)].push_back(qr);
if (qr.r <= mid) hang(l, mid, qr);
else hang(mid + 1, r, qr);
} inline void solve(const int l, const int r) {
if (l == r) return ;
int mid = l + r >> 1; auto& qvec(ask[TID(l, r)]);
solve(l, mid), solve(mid + 1, r);
if (qvec.empty()) return ; LL curs = 0; static std::set<int> st;
auto insert = [&](const int x)->PII {
auto&& it(st.insert(x).first); int p = 0, q = 0;
if (std::next(it) != st.end()) q = *std::next(it);
if (it != st.begin()) p = *std::prev(it);
if (p) curs += iabs(ref[x] - ref[p]);
if (q) curs += iabs(ref[x] - ref[q]);
if (p && q) curs -= iabs(ref[p] - ref[q]);
return { p, q ? q : n + 1 };
}; auto bondL = [&](const int x, const int y, const int op)->void {
if (x + 1 == y) return ;
int k = sgt.qmin(1, 1, n, x + 1, y - 1);
if (!(1 <= k && k <= n)) return ;
int dlt = (1 <= x ? -ref[x] : 0) + (y <= n ? -ref[y] : 0)
+ (1 <= x && y <= n ? -iabs(ref[x] - ref[y]) : 0);
bit.add(k, op * dlt);
};
bit.restore(), st.clear(), curs = 0;
rep (i, mid + 1, r) sgt.modify(1, 1, n, a[i], i);
std::sort(qvec.begin(), qvec.end(),
[](const Query& u, const Query& v) { return u.l > v.l; });
for (int i = mid, j = 0; i >= l && j != qvec.size(); --i) {
PII p = insert(a[i]);
bondL(p.fi, a[i], 1), bondL(a[i], p.se, 1), bondL(p.fi, p.se, -1);
for (; j != qvec.size() && qvec[j].l == i; ++j) {
ans[qvec[j].id] += curs + bit.sum(qvec[j].r);
}
}
rep (i, mid + 1, r) sgt.modify(1, 1, n, a[i], 0); auto bondR = [&](const int x, const int y, const int op)->void {
if (x + 1 == y) return ;
int k = sgt.qmax(1, 1, n, x + 1, y - 1);
if (!(1 <= k && k <= n)) return ;
int dlt = (1 <= x ? ref[x] : 0) + (y <= n ? ref[y] : 0)
+ (1 <= x && y <= n ? -iabs(ref[x] - ref[y]) : 0);
bit.add(n - k + 1, op * dlt);
};
bit.restore(), st.clear(), curs = 0;
rep (i, l, mid) sgt.modify(1, 1, n, a[i], i);
std::sort(qvec.begin(), qvec.end(),
[](const Query& u, const Query& v) { return u.r < v.r; });
for (int i = mid + 1, j = 0; i <= r && j != qvec.size(); ++i) {
PII p = insert(a[i]);
bondR(p.fi, a[i], 1), bondR(a[i], p.se, 1), bondR(p.fi, p.se, -1);
for (; j != qvec.size() && qvec[j].r == i; ++j) {
ans[qvec[j].id] += curs + bit.sum(n - qvec[j].l + 1);
}
}
rep (i, l, mid) sgt.modify(1, 1, n, a[i], 0);
} int main() {
n = rint(), q = rint();
rep (i, 1, n) ref[a[i] = rint()] = i;
rep (i, 1, q) {
int l = rint(), r = rint();
if (l != r) hang(1, n, { l, r, i });
} sgt.build(1, 1, n), solve(1, n);
rep (i, 1, q) wint(ans[i]), putchar('\n');
return 0;
}

Solution -「WC 2022」秃子酋长的更多相关文章

  1. Diary / Solution Set -「WC 2022」线上冬眠做噩梦

      大概只有比较有意思又不过分超出能力范围的题叭.   可是兔子的"能力范围" \(=\varnothing\) qwq. 「CF 1267G」Game Relics   任意一个 ...

  2. 「WC 2019」数树

    「WC 2019」数树 一道涨姿势的EGF好题,官方题解我并没有完全看懂,尝试用指数型生成函数和组合意义的角度推了一波.考场上只得了 44 分也暴露了我在数数的一些基本套路上的不足,后面的 \(\ex ...

  3. Solution -「ARC 104E」Random LIS

    \(\mathcal{Description}\)   Link.   给定整数序列 \(\{a_n\}\),对于整数序列 \(\{b_n\}\),\(b_i\) 在 \([1,a_i]\) 中等概率 ...

  4. Solution -「CTS 2019」「洛谷 P5404」氪金手游

    \(\mathcal{Description}\)   Link.   有 \(n\) 张卡牌,第 \(i\) 张的权值 \(w_i\in\{1,2,3\}\),且取值为 \(k\) 的概率正比于 \ ...

  5. Solution -「BZOJ 3812」主旋律

    \(\mathcal{Description}\)   Link.   给定含 \(n\) 个点 \(m\) 条边的简单有向图 \(G=(V,E)\),求 \(H=(V,E'\subseteq E)\ ...

  6. Solution -「CF 1342E」Placing Rooks

    \(\mathcal{Description}\)   Link.   在一个 \(n\times n\) 的国际象棋棋盘上摆 \(n\) 个车,求满足: 所有格子都可以被攻击到. 恰好存在 \(k\ ...

  7. Solution -「简单 DP」zxy 讲课记实

    魔法题位面级乱杀. 「JOISC 2020 Day4」治疗计划 因为是不太聪明的 Joker,我就从头开始理思路了.中途也会说一些和 DP 算法本身有关的杂谈,给自己的冗长题解找借口. 首先,治疗方案 ...

  8. Solution -「基环树」做题记录

    写的大多只是思路,比较简单的细节和证明过程就不放了,有需者自取. 基环树简介 简单说一说基环树吧.由名字扩展可得这是一类以环为基础的树(当然显然它不是树. 通常的表现形式是一棵树再加一条非树边,把图画 ...

  9. 「WC 2007」剪刀石头布

    题目链接 戳我 \(Solution\) 直接求很明显不太好求,于是考虑不构成剪刀石头布的情况. 我们现在假设一个人\(i\)赢了\(x\)场,那么就会有\(\frac{x*(x-1)}{2}\) 我 ...

随机推荐

  1. [Win32] UAC用户账户控制 (提权)

    最近写程序时遇到一个问题,就是当一个程序需要管理员权限才能正常运行该怎么办? 通过查阅多方资料,我总结出来几个比较实用的办法(每种办法实现方法不同,同时功能上也有一些小小的差异) 方法一(批处理脚本) ...

  2. javax.el.PropertyNotFoundException: 类型[xx.xxx.xxxx]上找不到属性[xxxx]

    今天在JSP利用EL表达式取值报了 "javax.el.PropertyNotFoundException" 1 Caused by: org.apache.jasper.Jasp ...

  3. Zookeeper绍二(分布式锁介)

    一.为什么会有分布式锁? 在多线程环境下,由于上下文的切换,数据可能出现不一致的情况或者数据被污染,我们需要保证数据安全,所以想到了加锁. 所谓的加锁机制呢,就是当一个线程访问该类的某个数据时,进行保 ...

  4. Nginx高级模块学习

    Nginx的rewrite规则 实现url重写一级重定向 使用场景: 1.URL访问跳转,支持开发设计 页面跳转.兼容性支持.展示效果 2.SEO优化 3.维护 后台维护.流量转发等 4.安全 配置语 ...

  5. 校招——面试(Android岗)总结

    PS:持续更新,未完待续 2016.8.24某为面试 自我介绍一下 链表和数组的区别 数组的存储空间是静态.连续分布的,初始化过大会造成空间浪费,过小会使空间溢出:链表的存储空间是动态分布的,只要内存 ...

  6. rocketmq实现延迟队列精确到秒级实现方案2-时间轮和delay-file实现

    上图是通过RocketMQ源码分析一个实现原理方案示意图. 分为两个部分: 消息的写入消息的Schedule 在写入CommitLog之前,如果是延迟消息,按照每10分钟写入delayfile文件,对 ...

  7. actf2020 exec

    actf2020 exec 1.根据提示,ping一个127.0.0.1,有回显,ls一下发现index.php 3.方向找错了,绕了一大圈,还cat了index.php也没发现什么 最后没招了,回原 ...

  8. C++普通成员函数的调用形式

    #include<iostream> using namespace std; class A { public: int data; void foo(int x) { data = x ...

  9. java内部类-局部内部类

    1 package face_09; 2 /* 3 * 内部类可以存放在局部位置上. 4 * 5 * 内部类在局部位置上只能访问局部中被final修饰的局部变量. 6 */ 7 /*class Out ...

  10. (2)RabbitMQ架构设计与应用场景

    1.什么是消息中间件? 消息是指应用间传输的数据.消息体包括文本字符串.Json.内嵌对象等.消息中间件是基于队列模型实现异步和同步传输数据的.作用:解耦,冗余(存储).扩展性.削峰.可恢复性.顺序保 ...