线段树+平衡树

我!又!被!卡!常!了!

以前的splay偷懒的删除找前驱后继的办法被卡了QAQ

放一个在洛谷开O2才能过的代码。。我太菜了。。

#include <bits/stdc++.h>
#define INF 2147483647
#define rint register int
#define full(a, b) memset(a, b, sizeof a)
using namespace std;
typedef long long ll;
inline int lowbit(int x){ return x & (-x); }
inline int read(){
int X = 0, w = 0; char ch = 0;
while(!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
while(isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
return w ? -X : X;
}
static short c[20], top;
inline void print(int x){
if(!x){ putchar(48); putchar('\n'); return;}
if(x < 0) putchar('-'),x *= -1;
for(top = 0; x ; c[++top] = x % 10, x /= 10);
for(; top; putchar(c[top--]^48));
putchar('\n');
}
inline int gcd(int a, int b){ return a % b ? gcd(b, a % b) : b; }
inline int lcm(int a, int b){ return a / gcd(a, b) * b; }
template<typename T>
inline T max(T x, T y, T z){ return max(max(x, y), z); }
template<typename T>
inline T min(T x, T y, T z){ return min(min(x, y), z); }
template<typename A, typename B, typename C>
inline A fpow(A x, B p, C lyd){
A ans = 1;
for(; p; p >>= 1, x = 1LL * x * x % lyd)if(p & 1)ans = 1LL * x * ans % lyd;
return ans;
} const int N = 3000005;
int n, m, tot, tmp, root[N], val[N], size[N], fa[N], ch[N][2], cnt[N], a[N]; inline int init(rint v, rint f){
++tot;
val[tot] = v, fa[tot] = f, size[tot] = cnt[tot] = 1;
ch[tot][0] = ch[tot][1] = 0;
return tot;
} inline void push_up(rint x){
size[x] = size[ch[x][0]] + size[ch[x][1]] + cnt[x];
} inline void rotate(rint x){
int y = fa[x], z = fa[y], p = (ch[y][1] == x) ^ 1;
ch[y][p^1] = ch[x][p], fa[ch[x][p]] = y;
ch[z][ch[z][1] == y] = x, fa[x] = z;
ch[x][p] = y, fa[y] = x;
push_up(y), push_up(x);
} inline void splay(rint i, rint x, rint goal){
if(x == goal) return;
while(fa[x] != goal){
int y = fa[x], z = fa[y];
if(z != goal){
(ch[y][0] == x) ^ (ch[z][0] == y) ? rotate(x) : rotate(y);
}
rotate(x);
}
push_up(x);
if(goal == 0) root[i] = x;
} inline void insert(rint i, rint x){
if(!root[i]){
root[i] = init(x, 0);
return;
}
rint cur = root[i];
while(ch[cur][x > val[cur]]){
if(x == val[cur]) break;
cur = ch[cur][x > val[cur]];
}
if(x == val[cur]) cnt[cur] ++, splay(i, cur, 0);
else ch[cur][x > val[cur]] = init(x, cur), splay(i, ch[cur][x > val[cur]], 0);
} inline void find(rint i, rint x){
if(!root[i]) return;
rint cur = root[i];
while(x != val[cur] && ch[cur][x > val[cur]])
cur = ch[cur][x > val[cur]];
splay(i, cur, 0);
} /*inline int precursor(rint i, rint x){
find(i, x);
if(val[root[i]] < x) return root[i];
rint cur = ch[root[i]][0];
while(ch[cur][1]) cur = ch[cur][1];
return cur;
} inline int successor(rint i, rint x){
find(i, x);
if(val[root[i]] > x) return root[i];
rint cur = ch[root[i]][1];
while(ch[cur][0]) cur = ch[cur][0];
return cur;
}*/ inline int precursor(int i, int v){
int x = root[i], ans = -INF;
while (x){
if (val[x] < v){
if (ans < val[x]) ans = val[x];
x = ch[x][1];
}
else x = ch[x][0];
}
return ans;
} inline int successor(int i, int v){
int x = root[i], ans = INF;
while (x){
if (val[x] > v){
if (ans > val[x]) ans = val[x];
x = ch[x][0];
}
else x = ch[x][1];
} return ans;
} inline void remove(rint i, rint x){
rint pre = precursor(i, x), suc = successor(i, x);
splay(i, pre, 0), splay(i, suc, root[i]);
rint key = ch[suc][0];
if(cnt[key] > 1) cnt[key] --, splay(i, key, 0);
else ch[suc][0] = 0;
push_up(suc);
} inline void clear(int x){
fa[x] = ch[x][0] = ch[x][1] = size[x] = cnt[x] = val[x] = 0;
} inline void del(rint i, rint x){
find(i, x);
int cur = root[i];
if(cnt[cur] > 1){
cnt[cur] --;
return;
}
if(!ch[cur][0]){
int y = ch[cur][1];
root[i] = y, fa[y] = 0;
return;
}
if(!ch[cur][1]){
int y = ch[cur][0];
root[i] = y, fa[y] = 0;
return;
}
int p = ch[cur][0];
while(ch[p][1]) p = ch[p][1];
int oldrt = root[i];
splay(i, p, 0);
ch[root[i]][1] = ch[oldrt][1];
fa[ch[oldrt][1]] = root[i];
clear(oldrt);
push_up(root[i]);
return;
} void buildTree(rint rt, rint l, rint r){
insert(rt, INF), insert(rt, -INF);
if(l == r) return;
rint mid = (l + r) >> 1;
buildTree(rt << 1, l, mid);
buildTree(rt << 1 | 1, mid + 1, r);
push_up(rt);
} void segInsert(rint rt, rint l, rint r, rint k, rint x){
insert(rt, x);
if(l == r) return;
rint mid = (l + r) >> 1;
if(k <= mid) segInsert(rt << 1, l, mid, k, x);
else segInsert(rt << 1 | 1, mid + 1, r, k, x);
} int segRank(rint rt, rint l, rint r, rint x, rint ql, rint qr){
if(l == ql && r == qr){
find(rt, x);
if(val[root[rt]] >= x) return size[ch[root[rt]][0]] - 1;
return size[ch[root[rt]][0]] + cnt[root[rt]] - 1;
}
rint mid = (l + r) >> 1;
if(qr <= mid) return segRank(rt << 1, l, mid, x, ql, qr);
else if(ql > mid) return segRank(rt << 1 | 1, mid + 1, r, x, ql, qr);
return segRank(rt << 1, l, mid, x, ql, mid) + segRank(rt << 1 | 1, mid + 1, r, x, mid + 1, qr);
} void segModify(rint rt, rint l, rint r, rint pos, rint k){
insert(rt, k), del(rt, a[pos]);
if(l == r) return;
rint mid = (l +r) >> 1;
if(pos <= mid) segModify(rt << 1, l, mid, pos, k);
else segModify(rt << 1 | 1, mid + 1, r, pos, k);
} int segPrecursor(rint rt, rint l, rint r, rint x, rint ql, rint qr){
if(l == ql && r == qr){
return precursor(rt, x);
}
rint mid = (l + r) >> 1;
if(qr <= mid) return segPrecursor(rt << 1, l, mid, x, ql, qr);
else if(ql > mid) return segPrecursor(rt << 1 | 1, mid + 1, r, x, ql, qr);
return max(segPrecursor(rt << 1, l, mid, x, ql, mid), segPrecursor(rt << 1 | 1, mid + 1, r, x, mid + 1, qr));
} int segSuccessor(rint rt, rint l, rint r, rint x, rint ql, rint qr){
if(l == ql && r == qr){
return successor(rt, x);
}
rint mid = (l + r) >> 1;
if(qr <= mid) return segSuccessor(rt << 1, l, mid, x, ql, qr);
else if(ql > mid) return segSuccessor(rt << 1 | 1, mid + 1, r, x, ql, qr);
return min(segSuccessor(rt << 1, l, mid, x, ql, mid), segSuccessor(rt << 1 | 1, mid + 1, r, x, mid + 1, qr));
} inline int select(rint l, rint r, rint k){
rint ll = 0, rr = tmp;
while(ll < rr){
rint mid = (ll + rr + 1) >> 1;
if(segRank(1, 1, n, mid, l, r) + 1 > k) rr = mid - 1;
else ll = mid;
}
return ll;
} int main(){ //freopen("data.txt","r",stdin); //clock_t startTime = clock(); n = read(), m = read();
tmp = -INF;
buildTree(1, 1, n);
for(rint i = 1; i <= n; i ++) a[i] = read(), tmp = max(tmp, a[i]), segInsert(1, 1, n, i, a[i]);
while(m --){
rint opt = read();
if(opt == 1){
rint l = read(), r = read(), k = read();
print(segRank(1, 1, n, k, l, r) + 1);
//printf("%d\n", segRank(1, 1, n, k, l, r) + 1);
}
else if(opt == 2){
rint l = read(), r = read(), k = read();
print(select(l, r, k));
//printf("%d\n", select(l, r, k));
}
else if(opt == 3){
rint pos = read(), k = read();
segModify(1, 1, n, pos, k);
a[pos] = k;
}
else if(opt == 4){
rint l = read(), r = read(), k = read();
print(segPrecursor(1, 1, n, k, l, r));
//printf("%d\n", segPrecursor(1, 1, n, k, l, r));
}
else if(opt == 5){
rint l = read(), r = read(), k = read();
print(segSuccessor(1, 1, n, k, l, r));
//printf("%d\n", segSuccessor(1, 1, n, k, l, r));
}
} //clock_t endTime = clock(); //cout << "time: " << double(endTime - startTime) / CLOCKS_PER_SEC << " s" << endl; return 0;
}

洛谷P3380 二逼平衡树的更多相关文章

  1. 洛谷P3380 【模板】二逼平衡树(树套树)(线段树+树状数组)

    P3380 [模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数 ...

  2. 洛谷 P3380 【模板】二逼平衡树(树套树)-线段树套splay

    P3380 [模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数 ...

  3. 洛谷 P3380 bzoj3196 Tyvj1730 【模板】二逼平衡树(树套树)

    [模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数值 查询k在 ...

  4. P3380 【模板】二逼平衡树(树套树)(线段树套平衡树)

    P3380 [模板]二逼平衡树(树套树) 前置芝士 P3369 [模板]普通平衡树 线段树套平衡树 这里写的是线段树+splay(不吸氧竟然卡过了) 对线段树的每个节点都维护一颗平衡树 每次把给定区间 ...

  5. 【题解】二逼平衡树 [P3380] [BZOJ3196] [Tyvj1730]

    [题解]二逼平衡树 [P3380] [BZOJ3196] [Tyvj1730] 传送门:[模板]二逼平衡树(树套树)\([P3380]\) \([BZOJ3196]\) \([TYVJ1730]\) ...

  6. bzoj 3196: Tyvj 1730 二逼平衡树

    #include<cstdio> #include<ctime> #include<cstdlib> #include<iostream> #defin ...

  7. 【BZOJ-3196】二逼平衡树 线段树 + Splay (线段树套平衡树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2271  Solved: 935[Submit][Stat ...

  8. 【BZOJ 3196】二逼平衡树 线段树套splay 模板题

    我写的是线段树套splay,网上很多人写的都是套treap,然而本蒟蒻并不会treap 奉上sth神犇的模板: //bzoj3196 二逼平衡树,支持修改某个点的值,查询区间第k小值,查询区间某个值排 ...

  9. bzoj 3196 Tyvj 1730 二逼平衡树(线段树套名次树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1807  Solved: 772[Submit][Stat ...

随机推荐

  1. MySQL 笔记整理(11) --怎么给字符串字段加索引?

    笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 11) --怎么给字符串字段加索引? 日常工作中的登录系统,你很可能会使 ...

  2. 将传统 WPF 程序迁移到 DotNetCore 3.0

    介绍 由于历史原因,基于 Windows 平台存在着大量的基于 .NetFramework 开发的 WPF 和 WinForm 相关程序,如果将这些程序全部基于 DotNetCore 3.0 重写一遍 ...

  3. 微擎模块的安装文件manifest.xml

    微擎在安装或卸载模块时会根据manifest.xml生成(或删除)数据库中相应记录,并执行manifest.xml里指定的脚本. manifest.xml文件内容详细介绍如下: manifest - ...

  4. IOS跟ANDROID的区别

    大家总是会纠结哪个手机系统会更加适合自己,那就由小编我简要介绍一下IOS和安卓的区别吧! 运行机制:安卓是虚拟机运行机制,IOS是沙盒运行机制.这里再说明一下这两者的主要不同之处.安卓系统中应用程序的 ...

  5. jquery各大学选择插件

    地址:http://www.jq22.com/jquery-info5565 演示地址:http://www.jq22.com/yanshi5565

  6. WinForm 双向数据绑定

    程序目标: 控件的属性值与对象的属性值双向绑定使窗口控件的属性值与对象的属性值保持一致.对窗口控件属性值更改后立即更新对象的属性值,对对象的属性值更改后立即更新窗口控件的属性值. 程序完整代码包:ht ...

  7. Mysql 创建事件任务

    DELIMITER $$ CREATE DEFINER=`root`@`%` EVENT `test` ON SCHEDULE EVERY 1 DAY STARTS '2019-02-12 00:00 ...

  8. 如何保持Redis和MySQL数据一致

    原文:https://blog.csdn.net/thousa_ho/article/details/78900563 1. MySQL持久化数据,Redis只读数据 redis在启动之后,从数据库加 ...

  9. 【转】C# 定时器事件(设置时间间隔,间歇性执行某一函数,控制台程序)

    using System.Timers;定时器事件代码 static void Main(string[] args) { Method(); #region 定时器事件 Timer aTimer = ...

  10. Mysql Navicat数据库定时备份,定时删除

    Navicat自带实现数据库定时备份 1.先点击需要备份的数据库,然后点击计划,再点击新建批处理作业 2.然后出现双机可用任务列表,然后在已选择的任务中会出现可用任务 3. 点击保存,弹出对话框,给这 ...