【整体二分】【P3834】 【模板】可持久化线段树 1(主席树)
Description
给定一个长度为 的序列, 次操作静态查询区间第 大
Input
第一行是
下一行描述这个序列
下面 行描述操作
Output
每个查询输出一行一个数代表答案
Hint
值域为
Solution
考虑整体二分。
将操作和序列全部离线,混在一起操作,在每层中,如果一个插入操作插入的数大于 mid,则压入右边的vector,否则压入左边的vector,这样即可保证在每一层整个序列的插入操作只被操作 次。用树状数组维护不大于 mid 的插入点,插入点个数不小于 的查询压入左侧,否则 ,压入右侧即可。
注意一个区间内没有操作的时候要剪枝,否则复杂度会加上值域。
总复杂度
Code
// luogu-judger-enable-o2
#include <cstdio>
#include <vector>
#include <iostream>
#ifdef ONLINE_JUDGE
#define freopen(a, b, c)
#endif
typedef long long int ll;
namespace IPT {
const int L = 1000000;
char buf[L], *front=buf, *end=buf;
char GetChar() {
if (front == end) {
end = buf + fread(front = buf, 1, L, stdin);
if (front == end) return -1;
}
return *(front++);
}
}
template <typename T>
inline void qr(T &x) {
char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
if (lst == '-') x = -x;
}
namespace OPT {
char buf[120];
}
template <typename T>
inline void qw(T x, const char aft, const bool pt) {
if (x < 0) {x = -x, putchar('-');}
int top=0;
do {OPT::buf[++top] = static_cast<char>(x % 10 + '0');} while (x /= 10);
while (top) putchar(OPT::buf[top--]);
if (pt) putchar(aft);
}
const int maxn = 200010;
const int INF = 1000000010;
struct OP {
int l, r, k, id;
};
std::vector<OP> Q;
int n, m;
int ans[maxn], tree[maxn];
int lowbit(int);
int query(int);
void update(int, const int);
void divide(int, int, std::vector<OP>&);
int main() {
freopen("1.in", "r", stdin);
qr(n); qr(m);
for (int i = 1, x; i <= n; ++i) {
x = 0; qr(x); Q.push_back({-1, 0, x, i});
}
for (int i = 1, a, b, c; i <= m; ++i) {
a = b = c = 0; qr(a); qr(b); qr(c);
Q.push_back({a, b, c, i});
}
divide(-INF, INF, Q);
for (int i = 1; i <= m; ++i) qw(ans[i], '\n', true);
return 0;
}
void divide(int l, int r, std::vector<OP> &v) {
if (!v.size()) return;
if (l == r) {
for (auto i : v) if (i.l != -1) ans[i.id] = l;
return;
}
std::vector<OP>ldown, rdown;
int mid = (l + r) >> 1;
for (auto i : v) {
if (i.l == -1) {
if (i.k <= mid) {
update(i.id, 1);
ldown.push_back(i);
} else rdown.push_back(i);
}
}
for (auto i : v) {
if (i.l != -1) {
int k = query(i.r) - query(i.l - 1);
if ((k) >= i.k) ldown.push_back(i);
else {
i.k -= k; rdown.push_back(i);
}
}
}
for (auto i : ldown) {
if (i.l == -1) update(i.id, -1);
}
divide(l, mid, ldown);
divide(mid + 1, r, rdown);
}
inline int lowbit(int x) {return x & -x;}
void update(int x, const int v) {
while (x <= n) {
tree[x] += v;
x += lowbit(x);
}
}
int query(int x) {
int _ret = 0;
while (x) {
_ret += tree[x];
x -= lowbit(x);
}
return _ret;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具