【Ynoi 2016】掉进兔子洞
Luogu P4688 掉进兔子洞
题意
给定一个长度为
有
数据范围与约定
题解
首先发现,每次询问的答案形式为:
所以只要我们有办法求出
我们可以在离散化上下手,令一个颜色离散化后的值为:序列中,小于这个数的个数加
这样有一个好处,我们假设当前颜色为
最后一个问题,怎么求每个区间的 bitset?考虑到这个 bitset 因为我们离散化比较特殊的原因,没办法通过区间合并来快速得到,所以不能使用分块或者线段树之类的数据结构了。所以我们考虑使用莫队。
这里有一个问题,我们开不下
代码
#include<bits/stdc++.h> using namespace std; /*====================*/ #define endl "\n" /*====================*/ typedef long long lnt; /*====================*/ const int N = 1e5 + 10; const int M = 1e5 + 10; const int S1 = 4e4;//对询问分组 const int S2 = 350;//对莫队分组 /*====================*/ int n, m; int arr[N]; /*====================*/ struct Query { int l, r, idx; Query(int _l = 0, int _r = 0, int _idx = 0) { l = _l, r = _r, idx = _idx; } friend bool operator<(const Query& a, const Query& b) { return (a.l / S2 == b.l / S2) ? (((a.l / S2) & 1) ? (a.r > b.r) : (a.r < b.r)) : (a.l < b.l); } }query[3 * M]; /*====================*/ int ans[M]; /*====================*/ int cnt[N]; bitset<N>temp; bitset<N>state[S1]; void Add(int pos) { temp[arr[pos] + ++cnt[arr[pos]] - 1] = 1; } void Del(int pos) { temp[arr[pos] + cnt[arr[pos]]-- - 1] = 0; } void Mo(int idxl, int idxr) { int askl = (idxl - 1) * 3 + 1; int askr = (idxr - 1) * 3 + 3; sort(query + askl, query + askr + 1); /*====================*/ temp.reset(); for (int i = idxl; i <= idxr; ++i) { state[i % S1].set(); } memset(cnt, 0, sizeof(cnt)); /*====================*/ int l = 1, r = 0; for (int i = askl; i <= askr; ++i) { while (query[i].l < l)Add(--l); while (r < query[i].r)Add(++r); while (l < query[i].l)Del(l++); while (query[i].r < r)Del(r--); state[query[i].idx % S1] &= temp; } /*====================*/ for (int i = idxl; i <= idxr; ++i) { ans[i] -= 3 * state[i % S1].count(); } } /*====================*/ void Solve(void) { do { cin >> n >> m; for (int i = 1; i <= n; ++i) { cin >> arr[i]; } } while (false);//读入 do { vector<int>lib; for (int i = 1; i <= n; ++i) { lib.push_back(arr[i]); } sort(lib.begin(), lib.end()); for (int i = 1; i <= n; ++i) { arr[i] = lower_bound(lib.begin(), lib.end(), arr[i]) - lib.begin() + 1; } } while (false);//离散化 do { int idxl = 1, idxr = S1; idxr = min(idxr, m); while (idxl <= idxr) { for (int i = idxl; i <= idxr; ++i) { for (int j = 1; j <= 3; ++j) { int l, r; cin >> l >> r; query[(i - 1) * 3 + j] = Query(l, r, i); ans[i] += r - l + 1; } } Mo(idxl, idxr); idxl += S1, idxr += S1; idxr = min(idxr, m); } } while (false);//莫队 do { for (int i = 1; i <= m; ++i) { cout << ans[i] << endl; } } while (false);//输出 } /*====================*/ int main() { #ifndef ONLINE_JUDGE freopen("IN.txt", "r+", stdin); #endif ios::sync_with_stdio(false); cin.tie(NULL), cout.tie(NULL); int T = 1; //cin >> T; while (T--)Solve(); return 0; }
分类:
算法题解 / Ynoi
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话