考虑分块,每个块都是用 链表 维护的,并保证 \(size\) 和分块相当。

我们考虑一下怎么去查询,很显然,可以对值域分块,单点修改,记录前缀和,完全ojbk了,对每个块维护一个 \(pre , prb\) 数组

\(pre_{i,j}\) 数组表示 \(1~i\) 这些块中,出现了多少个 \(j\)

\(prb_{i,j}\) 数组表示 \(1~i\) 这些块中,在值域块 \(j\) 的有多少个

零散部分查一查就好了,修改也是稳定 \(\sqrt n\) 的,插入也是。

// powered by c++11
// by Isaunoya
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <bits/stdc++.h>
#define rep(i, x, y) for (register int i = (x); i <= (y); ++i)
#define Rep(i, x, y) for (register int i = (x); i >= (y); --i)
using namespace std;
using db = double;
using ll = long long;
using uint = unsigned int;
using pii = pair<int, int>;
#define ve vector
#define Tp template
#define all(v) v.begin(), v.end()
#define sz(v) ((int)v.size())
#define pb emplace_back
#define fir first
#define sec second
// the cmin && cmax
Tp<class T> void cmax(T& x, const T& y) {
if (x < y) x = y;
}
Tp<class T> void cmin(T& x, const T& y) {
if (x > y) x = y;
}
// sort , unique , reverse
Tp<class T> void sort(ve<T>& v) { sort(all(v)); }
Tp<class T> void unique(ve<T>& v) {
sort(all(v));
v.erase(unique(all(v)), v.end());
}
Tp<class T> void reverse(ve<T>& v) { reverse(all(v)); }
const int SZ = 0x191981;
struct FILEIN {
char qwq[SZ], *S = qwq, *T = qwq, ch;
char GETC() { return (S == T) && (T = (S = qwq) + fread(qwq, 1, SZ, stdin), S == T) ? EOF : *S++; }
FILEIN& operator>>(char& c) {
while (isspace(c = GETC()))
;
return *this;
}
FILEIN& operator>>(string& s) {
while (isspace(ch = GETC()))
;
s = ch;
while (!isspace(ch = GETC())) s += ch;
return *this;
}
Tp<class T> void read(T& x) {
bool sign = 1;
while ((ch = GETC()) < 0x30)
if (ch == 0x2d) sign = 0;
x = (ch ^ 0x30);
while ((ch = GETC()) > 0x2f) x = x * 0xa + (ch ^ 0x30);
x = sign ? x : -x;
}
FILEIN& operator>>(int& x) { return read(x), *this; }
FILEIN& operator>>(unsigned& x) { return read(x), *this; }
} in;
struct FILEOUT {
const static int LIMIT = 0x114514;
char quq[SZ], ST[0x114];
signed sz, O;
~FILEOUT() { flush(); }
void flush() {
fwrite(quq, 1, O, stdout);
fflush(stdout);
O = 0;
}
FILEOUT& operator<<(char c) { return quq[O++] = c, *this; }
FILEOUT& operator<<(string str) {
if (O > LIMIT) flush();
for (char c : str) quq[O++] = c;
return *this;
}
Tp<class T> void write(T x) {
if (O > LIMIT) flush();
if (x < 0) {
quq[O++] = 0x2d;
x = -x;
}
do {
ST[++sz] = x % 0xa ^ 0x30;
x /= 0xa;
} while (x);
while (sz) quq[O++] = ST[sz--];
return;
}
FILEOUT& operator<<(int x) { return write(x), *this; }
FILEOUT& operator<<(unsigned x) { return write(x), *this; }
} out;
int n, m;
const int maxn = 7e4 + 47;
const int blc = 235;
const int S = 300;
list<int> s[S];
#define bl(x) ((x - 1) / S + 1)
int pre[maxn][S], prb[S][S], L[S], R[S], cnt[maxn], t[S], st[S << 1], top = 0, ans = 0;
inline int modify(list<int>& l, int x, int v) {
auto it = l.begin();
while (x--) ++it;
int res = *(it);
return *(it) = v, res;
}
inline void get(list<int>& l, int x, int y) {
auto it = l.begin();
while (x--) ++it;
while (y--) {
++cnt[st[++top] = *(it)], ++t[bl(*(it))], ++it;
}
}
void qry(int l, int r, int k) {
top = 0;
const int bL = bl(l), bR = bl(r);
if (bL == bR) {
get(s[bL], l - L[bL], r - l + 1);
for (int i = 1;; i++) {
if (k > t[i]) {
k -= t[i];
} else {
for (int j = L[i];; ++j)
if (k > cnt[j]) {
k -= cnt[j];
} else {
ans = j;
break;
}
break;
}
}
} else {
get(s[bL], l - L[bL], R[bL] - l + 1), get(s[bR], 0, r - L[bR] + 1);
for (int i = 1;; i++) {
if (k > t[i] + prb[i][bR - 1] - prb[i][bL]) {
k -= (t[i] + prb[i][bR - 1] - prb[i][bL]);
} else {
for (int j = L[i];; ++j)
if (k > cnt[j] + pre[j][bR - 1] - pre[j][bL]) {
k -= (cnt[j] + pre[j][bR - 1] - pre[j][bL]);
} else {
ans = j;
break;
}
break;
}
}
}
ans--;
for (int i = 0; i <= top; i++) {
t[bl(st[i])] = 0, cnt[st[i]] = 0;
}
}
inline void change(int x, int v) {
const int bel = bl(x);
int las = modify(s[bel], x - L[bel], v);
for (int i = bel; i <= blc; i++) {
--pre[las][i], --prb[bl(las)][i], ++pre[v][i], ++prb[bl(v)][i];
}
}
inline void ins(int x, int v) {
const int bel = bl(x);
auto it = s[bel].begin();
for (int i = x - L[bel]; i--;) ++it;
s[bel].insert(it, v);
for (int i = bel; i <= blc; i++) {
++pre[v][i], ++prb[bl(v)][i];
}
for (int i = bel + 1; i <= blc; i++) {
if (s[i - 1].size() <= S) {
break;
} else {
int las = s[i - 1].back();
--pre[las][i - 1], --prb[bl(las)][i - 1];
s[i - 1].pop_back(), s[i].push_front(las);
}
}
}
signed main() {
#ifdef _WIN64
freopen("testdata.in", "r", stdin);
#else
ios_base ::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
#endif
// code begin.
in >> n;
rep(i, 1, blc) { L[i] = R[i - 1] + 1, R[i] = L[i] + S - 1; }
rep(i, 1, n) {
int x;
const int bel = bl(i);
in >> x, ++x, s[bel].pb(x);
rep(j, bel, blc) { ++pre[x][j], ++prb[bl(x)][j]; }
}
in >> m;
while (m--) {
char c;
in >> c;
if (c == 'Q') {
int l, r, k;
in >> l >> r >> k, qry(l ^ ans, r ^ ans, k ^ ans), out << ans << '\n';
}
if (c == 'M') {
int x, v;
in >> x >> v, x ^= ans, v ^= ans, ++v, change(x, v);
}
if (c == 'I') {
int x, v;
in >> x >> v, x ^= ans, v ^= ans, ++v, ins(x, v);
}
}
return 0;
// code end.
}

「BZOJ3065」带插入区间K小值 [分块]的更多相关文章

  1. 【BZOJ3065】带插入区间K小值 替罪羊树+权值线段树

    [BZOJ3065]带插入区间K小值 Description 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理 ...

  2. 【bzoj3065】带插入区间K小值 替罪羊树套权值线段树

    题目描述 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理性愉悦一下,查询区间k小值.他每次向它的随从伏特提出 ...

  3. 【BZOJ3065】带插入区间k小值

    题意: 带插入,修改的区间k小值在线查询 原序列长度<=35000,插入个数<=35000,修改个数<=70000,0<=权值<=70000 题解: Orz vfleak ...

  4. 【bzoj3065】: 带插入区间K小值 详解——替罪羊套函数式线段树

    不得不说,做过最爽的树套树———— 由于有了区间操作,我们很容易把区间看成一棵平衡树,对他进行插入,那么外面一层就是平衡树了,这就与我们之前所见到的不同了.我们之前所见到的大多数是线段树套平衡树而此题 ...

  5. BZOJ3065:带插入区间K小值

    浅谈树状数组与主席树:https://www.cnblogs.com/AKMer/p/9946944.html 题目传送门:https://www.lydsy.com/JudgeOnline/prob ...

  6. [BZOJ3065]带插入区间K小值 解题报告 替罪羊树+值域线段树

    刚了一天的题终于切掉了,数据结构题的代码真**难调,这是我做过的第一道树套树题,做完后感觉对树套树都有阴影了......下面写一下做题记录. Portal Gun:[BZOJ3065]带插入区间k小值 ...

  7. bzoj 3065: 带插入区间K小值 替罪羊树 && AC300

    3065: 带插入区间K小值 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 1062  Solved: 253[Submit][Status] Des ...

  8. 【题解】BZOJ 3065: 带插入区间K小值——替罪羊树套线段树

    题目传送门 题解 orz vfk的题解 3065: 带插入区间K小值 系列题解 一 二 三 四 惨 一开始用了一种空间常数很大的方法,每次重构的时候merge两颗线段树,然后无限RE(其实是MLE). ...

  9. 3065: 带插入区间K小值_树套树_替罪羊树_权值线段树

    经过周六一天,周一3个小时的晚自习,周二2个小时的疯狂debug,终于凭借自己切掉了这道树套树题. Code: #include <cstdio> #include <algorit ...

随机推荐

  1. 【存储类、链接、存储管理】分配内存:malloc()、free()

    一.使用库函数:malloc()分配管理内存 (一)标识符(Identifier) 1. 定义变量时,使用了诸如 a.abc.mn123 这样的名字,它们都是程序员自己起的,一般能够表达出变量的作用, ...

  2. 时序数据库 Apache-IoTDB 源码解析之文件格式简介(三)

    上一章聊到在车联网或物联网中对数据库的需求,以及 IoTDB 的整体架构,详情请见: 时序数据库 Apache-IoTDB 源码解析之系统架构(二) 打一波广告,欢迎大家访问IoTDB 仓库,求一波 ...

  3. HTTP协议简单理解

    1.概念: “超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议.所有的WWW文件都必须遵守这个标准. 设计HTTP最初的目的是为了 ...

  4. 使用Gradle自动创建Java项目结构

    D:\N3verL4nd\Desktop\java>tree 卷 本地磁盘 的文件夹 PATH 列表 卷序列号为 00000200 0006:08B0 D:. ├─.gradle │ ├─3.4 ...

  5. 生成HTML测试报告表格

    #生成HTML测试报告 #-*- coding:utf-8 -*- from selenium import webdriver from selenium.webdriver.common.by i ...

  6. CCF_ 201403-3 _命令行选项

    不要怀疑,这题跟CCF_201604-3_路径解析一样恶心,很多中情况,要仔细读题,注意细节. 写的比较乱. #include<iostream> #include<cstdio&g ...

  7. 快速了解Lambda表达式-Java

    目录 lambda表达式 前言 简介 简单入门 用法 好处 总结 lambda表达式 前言 最近因为疫情,也不能正常返校什么的,希望大家都能好好的,希望武汉加油,中国加油,在家也看了很多视频,学了一点 ...

  8. PYTHON 学习笔记1 PYTHON 入门 搭建环境与基本类型

    简介 Python,当然大家听到这个名词不再是有关于像JAVA 一样的关于后台,我们学习Python 的目的在于对于以后数据分析和机器学习AI 奠定基础,Python 在数据分析这一块,可谓是有较好的 ...

  9. [REDIS 读书笔记]第一部分 数据结构与对象 跳跃表

    下面是跳跃表的基本原理,REDIS的实现大致相同 跳跃表的一个特点是,插入NODE是通过随机的方式来决定level的,比较奇特 下面是skipList的一个介绍,转载来的,源地址:http://ken ...

  10. JVM源码分析之临门一脚的OutOfMemoryError完全解读

    概述 OutOfMemoryError,说的是java.lang.OutOfMemoryError,是JDK里自带的异常,顾名思义,说的就是内存溢出,当我们的系统内存严重不足的时候就会抛出这个异常(P ...