BZOJ3065 带插入区间K小值 || 洛谷P4278
然鹅洛谷上时限被改然后只有20分......好像所有人都被卡了(雾)
由于替罪羊树不是依靠旋转操作而是依靠暴力重构的方式维护树的平衡,所以我们可以考虑使用替罪羊树套区间线段树的方式来水过去。
附上极其丑陋的代码,代码里面有解释......
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cctype>
using namespace std;
const double apl = 0.75;
struct seg_node { // 线段树节点
seg_node *ls, *rs;
int val;
}gt[], *tot, *Null;
vector< seg_node* > zt;
struct SG_node { // 替罪羊树节点
SG_node *ls, *rs;
int pos, size;
seg_node *root; // 该节点的线段树的根
bool isbad() { return max(ls->size, rs->size) > this->size * apl; }
}tc[], *bc[], *cnt, *null, *root;
int bc_top;
seg_node *new_seg_node (){ // 新的线段树的节点
seg_node *k; if( zt.size()) k = zt.back(), zt.pop_back();
else k = ++ tot;
k->ls = k->rs = Null; k->val = ; return k;
}
SG_node *new_SG_node (int val) { // 新的替罪羊树的节点
SG_node *k = bc_top ? bc[bc_top --] : ++ cnt;
k->pos = val; k->size = ;
k->ls = k->rs = null; k->root = Null; return k;
}
inline void init() { // 初始化
tot = gt; cnt = tc; Null = tot; null = cnt;
null->ls = null->rs = null; Null->ls = Null->rs = Null;
Null->val = ; ;
root = null; null->root = Null;
}
#define mid ( l + r >> 1)
inline void updata(seg_node *&x, int l, int r, int L, int o) { // 更新区间线段树
if( x == Null) x = new_seg_node();
) zt.push_back(x), x = Null; return ; }
if( L <= mid) updata(x->ls, l, mid, L, o);
, r, L, o);
x->val = x->ls->val + x->rs->val;
) zt.push_back(x), x = Null;
}
/* ----------------------------------------------------------------------------------------------
inline void updata(seg_node *&x, int l, int r, int L, int o) { // 更新区间线段树
if( x == Null) x = new_seg_node();
if( l == r) { x->val += o; return ; }
if( L <= mid) updata(x->ls, l, mid, L, o);
else updata(x->rs, mid+1, r, L, o);
x->val = x->ls->val + x->rs->val;
if( x->ls->val == 0 && x->ls != Null) zt.push_back(x->ls), x->ls = Null;
if( x->rs->val == 0 && x->rs != Null) zt.push_back(x->rs), x->rs = Null;
}比较下上下的区别,下面的在bzoj A了 但在洛谷RE了一整页......不就少回收了一个节点吗,为什么RE
-----------------------------------------------------------------------------------------------*/
int query(seg_node *x, int l, int r, int L) { // 查询区间线段树上小于L的数的个数
if( r < L || x == Null) return x->val;
if( L <= mid) return query(x->ls, l, mid, L);
, r, L);
}
inline void GG(seg_node *x) { if( x == Null) return ; zt.push_back(x); GG( x->ls); GG( x->rs); } // 回收线段树节点
];
inline void rca(SG_node *x) { if( x == null) return ; rca(x->ls); dis[++p] = x->pos; bc[++bc_top] = x; GG(x->root); rca(x->rs); } // 回收替罪羊树节点
inline void rbuild(SG_node *&x, int l, int r) { // 暴力重构替罪羊树
if( l > r) return ;
x = new_SG_node(dis[mid]); x->size = r - l + ;
rbuild(x->ls, l, mid-); rbuild(x->rs, mid+, r);
for ( int i = l; i <= r; i ++) // 更新当前线段树
updata(x->root, , , dis[i], );
}
inline void insert(SG_node *&x, int id, int val) { // 替罪羊树上插入新节点
, , val, ); return ; }
) insert(x->rs, id-x->ls->size-, val);
else insert(x->ls, id, val);
x->size ++; updata(x->root, , , val, );
, rca(x), rbuild(x, , p);
}
int change(SG_node *&x, int val, int id) { // 更改某一位置上的值
updata(x->root, , , val, ); int c;
) c = x->pos, x->pos = val;
) c = change(x->rs, val, id - x->ls->size - );
else c = change(x->ls, val, id);
updata(x->root, , , c, -);
return c;
}
vector < seg_node * > sc1; // 满足该节点以及其子节点都在询问区间【L , R】 内的线段树的根
vector < int > sc2; // 不满足 其子节点都在询问区间但该节点在询问区间的值
inline void search(SG_node *x, int l, int r) { // 查找询问区间
if( x == null || l > r) return ;
&& r == x->size) { sc1.push_back(x->root); return ; }
;
if( l <= k && r >= k) {
sc2.push_back(x->pos); search(x->ls, l, x->ls->size); search(x->rs, , r-k);
}
if( r < k) search(x->ls, l, r); if( l > k) search(x->rs, l-k, r-k);
}
int modify(int L, int R, int k) { // 二分查找答案
, r = ; search(root, L, R);
int t1 = sc1.size(), t2 = sc2.size();
sort(sc2.begin(), sc2.end());
while( l < r) {
;
; i < t1; i ++) ans += query(sc1[i], , , mid);
; i < t2; i ++) if( sc2[i] < mid) ans ++; else break;
if( ans >= k) r = mid;
;
}
sc1.clear(); sc2.clear(); ; // 为什么是 l - 1 自己YY
}
inline void G(int &x) { // 快读
x = ; ; ;
) + ( x << ) + ( o & ); x *= f;
}
int n, q, lastans;
];
int main() {
init(); G(n);
, a; i <= n; i ++) G(a), dis[i] = a; rbuild(root, , n);
G(q);
, x, y, z; i <= q; i ++) {
scanf("%s", s);
]) {
case 'Q' : G(x); G(y); G(z); x^=lastans; y^=lastans; z^=lastans; printf("%d\n", lastans = modify(x, y, z)); break;
case 'M' : G(x); G(y); x^=lastans; y^=lastans; change(root, y, x); break;
case 'I' : G(x); G(y); x^=lastans; y^=lastans; insert(root, x, y); break;
}
}
}
自从做了这道题,我发现我会用指针了......
感觉......指针 == 数组 ......

BZOJ3065 带插入区间K小值 || 洛谷P4278的更多相关文章
- [BZOJ3065]带插入区间K小值 解题报告 替罪羊树+值域线段树
刚了一天的题终于切掉了,数据结构题的代码真**难调,这是我做过的第一道树套树题,做完后感觉对树套树都有阴影了......下面写一下做题记录. Portal Gun:[BZOJ3065]带插入区间k小值 ...
- 【函数式权值分块】【块状链表】bzoj3065 带插入区间K小值
显然是块状链表的经典题.但是经典做法的复杂度是O(n*sqrt(n)*log^2(n))的,出题人明确说了会卡掉. 于是我们考虑每个块内记录前n个块的权值分块. 查询的时候差分什么的,复杂度就是O(n ...
- bzoj3065: 带插入区间K小值
无聊来写了下 一开始发现树高是O(n)的,然后就MLE了,进去看了下发现没有重构! 看了半天发现调用错了函数 然后进去又发现不满足sz = ch[0]->sz + ch[1]->sz + ...
- 【BZOJ3065】带插入区间K小值 替罪羊树+权值线段树
[BZOJ3065]带插入区间K小值 Description 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理 ...
- bzoj 3065: 带插入区间K小值 替罪羊树 && AC300
3065: 带插入区间K小值 Time Limit: 60 Sec Memory Limit: 512 MBSubmit: 1062 Solved: 253[Submit][Status] Des ...
- 【题解】BZOJ 3065: 带插入区间K小值——替罪羊树套线段树
题目传送门 题解 orz vfk的题解 3065: 带插入区间K小值 系列题解 一 二 三 四 惨 一开始用了一种空间常数很大的方法,每次重构的时候merge两颗线段树,然后无限RE(其实是MLE). ...
- 3065: 带插入区间K小值_树套树_替罪羊树_权值线段树
经过周六一天,周一3个小时的晚自习,周二2个小时的疯狂debug,终于凭借自己切掉了这道树套树题. Code: #include <cstdio> #include <algorit ...
- BZOJ 3065 带插入区间K小值(sag套线段树)
3065: 带插入区间K小值 Time Limit: 60 Sec Memory Limit: 512 MBSubmit: 4696 Solved: 1527[Submit][Status][Di ...
- 【学习笔记】浅析平衡树套线段树 & 带插入区间K小值
常见的树套树 一般来说,在嵌套数据结构中,线段树多被作为外层结构使用. 但线段树毕竟是 静态 的结构,导致了一些不便. 下面是一个难以维护的例子: 带插入区间 \(k\) 小值问题 来源:Luogu ...
随机推荐
- 使用Layered Window遇到的一些问题及解决方法
1. 使用Layered Window需要设置 WS_EX_LAYERED 属性 2. Layered Window不能作为Child Window 3. 它也不能包含子窗口,为什么呢,因为它收不到 ...
- vector向量容器
vector向量容器不但可以像数组一样对元素进行随机访问,还能在尾部插入元素,是一种简单高效的容器,可以代替数组. vector具有内存自动管理的功能,对于元素的插入和删除,可以动态的调整所占内存. ...
- PHP数组的详细解读
数组的定义 数组的本质是管理和操作一组变量,数组中可以存储任意长度的数据,也可以存储任意类型的数据.数组中的单元称为元素,每个元素包括下标(键)和值,访问元素的时候,是通过下标来访问,包括一维数组,二 ...
- while循环for循环优缺点和应用
while循环常用于那种不知道循环次数是多少的情况,比如让用户循环输入一个整数,直到输入某个特殊的字符为止,你根本没法直到这个循环会进行的次数. for循环多用于循环次数比较明确的情况,比如for(n ...
- logback.xml 实例
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="false ...
- (函数分治法)实现pow函数(x的y次方幂)
题目:实现pow函数. 题目分析:因为一个一个乘,循环太大,参考矩阵连乘问题:对于n=4的话,可以得出x的平方,然后平方与平方相乘.节省计算次数.对于偶数的幂,只要x的平方多次递归调用即可:对于奇数的 ...
- 20169219 NMap+Wireshark实验报告
Tcpdump介绍 用简单的话来定义tcpdump,就是:dump the traffic on a network,根据使用者的定义对网络上的数据包进行截获的包分析工具. tcpdump可以将网络中 ...
- SQL之TCL
TCL(Transaction Control Language)事务控制语言 COMMIT 提交SAVEPOINT 设置保存点ROLLBACK 回滚SET TRANSACTION
- vmware10安装Arch
必须保证机器能够上网! 1.vmware10中创建虚拟机(跟虚拟机中安装其他系统同样的操作). 2.开启上一步中创建的虚拟机. 3选择第一项进入 4自动进入root命令行 5进入 /dev (进行分区 ...
- LibreOJ 6000 搭配飞行员(最大流)
题解:最基础的最大流,按照主飞行员与起点建边,副飞行员与终点建边,可以同坐的主副飞行员之间建边,值均为一,然后跑一边最大流就完美了! 代码如下: #include<queue> #incl ...