您的位置:首页 > 其它

[BZOJ3196] [Tyvj1730] 二逼平衡树(线段树 套 Splay)

2017-05-18 14:56 393 查看

传送门

 

至少BZOJ过了,其他的直接弃。

 

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:

1.查询k在区间内的排名

2.查询区间内排名为k的值

3.修改某一位值上的数值

4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)

5.查询k在区间内的后继(后继定义为大于x,且最小的数)

 

最外层套一颗线段树,用来表示区间,线段树下面套个splay用来维护当前线段树节点的区间。

对于第二问可以二分,看看哪个数的排名为 k。

 

——代码

#include <iostream>
#include <cstring>
#include <cstdio>
#define root 1, 1, n
#define lson now << 1, l, mid
#define rson now << 1 | 1, mid + 1, r
#define ls son[now][0]
#define rs son[now][1]
#define debug puts("**************");

const int MAXN = 3500001, INF = 2147483647;

int n, m, sz;
int seq[MAXN], rt[MAXN];
int f[MAXN], son[MAXN][2], cnt[MAXN], key[MAXN], size[MAXN];

inline int read()
{
int f = 1, x = 0;
char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
return x * f;
}

inline int max(int x, int y)
{
return x > y ? x : y;
}

inline int min(int x, int y)
{
return x < y ? x : y;
}

inline void Splay_clear(int now)
{
f[now] = cnt[now] = key[now] = size[now] = ls = rs = 0;
}

inline void Splay_update(int now)
{
if(now)
{
size[now] = cnt[now];
if(ls) size[now] += size[ls];
if(rs) size[now] += size[rs];
}
}

inline int Splay_get(int x)
{
return son[f[x]][1] == x;
}

inline void Splay_rotate(int x)
{
int old = f[x], oldf = f[old], wh = Splay_get(x);

son[old][wh] = son[x][wh ^ 1];
f[son[old][wh]] = old;

son[x][wh ^ 1] = old;
f[old] = x;

if(oldf) son[oldf][son[oldf][1] == old] = x;
f[x] = oldf;

Splay_update(old);
Splay_update(x);
}

inline void Splay_splay(int x)
{
for(int fa; fa = f[x]; Splay_rotate(x))
if(f[fa])
Splay_rotate(Splay_get(x) ^ Splay_get(fa) ? x : fa);
}

inline void Splay_insert(int x, int k)
{
int now = rt[x], fa = 0;
if(!rt[x])
{
rt[x] = ++sz;
key[sz] = k;
size[sz] = cnt[sz] = 1;
return;
}
while(1)
{
if(k == key[now])
{
cnt[now]++;
Splay_update(now);
Splay_splay(now);
rt[x] = now;
return;
}
fa = now;
now = son[now][k > key[now]];
if(!now)
{
rt[x] = ++sz;
f[sz] = fa;
key[sz] = k;
size[sz] = cnt[sz] = 1;
son[fa][k > key[fa]] = sz;
//Splay_update(fa);
Splay_splay(sz);
return;
}
}
}

inline int Splay_findrank(int x, int k)
{
int now = rt[x], ans = 0;
while(1)
{
if(!now) return ans;
if(key[now] == k) return ans + size[ls];
else if(key[now] < k)
{
ans += cnt[now] + size[ls];
now = rs;
}
else now = ls;
}
}

inline int Splay_find(int x, int k)
{
int now = rt[x];
while(1)
{
if(key[now] > k) now = ls;
else if(key[now] < k) now = rs;
else
{
rt[x] = now;
Splay_splay(now);
return now;
}
}
}

inline int Splay_pre(int x)
{
int now = son[rt[x]][0];
while(rs) now = rs;
return now;
}

inline int Splay_suc(int x)
{
int now = son[rt[x]][1];
while(ls) now = ls;
return now;
}

inline void Splay_del(int x)
{
int now = rt[x];
if(cnt[now] > 1)
{
cnt[now]--;
Splay_update(now);
return;
}
if(!ls && !rs)
{
rt[x] = 0;
Splay_clear(now);
return;
}
if(!ls || !rs)
{
rt[x] = ls + rs;
f[rt[x]] = 0;
Splay_clear(now);
return;
}
int pre = Splay_pre(x);
Splay_splay(pre);
rt[x] = pre;
son[pre][1] = rs;
f[rs] = pre;
Splay_clear(now);
Splay_update(pre);
}

inline int Splay_findpre(int x, int k)
{
int now = rt[x], ans = -INF;
while(now)
{
if(key[now] < k)
{
ans = max(ans, key[now]);
now = rs;
}
else now = ls;
}
return ans;
}

inline int Splay_findsuc(int x, int k)
{
int now = rt[x], ans = INF;
while(now)
{
if(key[now] > k)
{
ans = min(ans, key[now]);
now = ls;
}
else now = rs;
}
return ans;
}

inline void SegTree_insert(int x, int k, int now, int l, int r)
{
Splay_insert(now, k);
if(l == r) return;
int mid = (l + r) >> 1;
if(x <= mid) SegTree_insert(x, k, lson);
else SegTree_insert(x, k, rson);
}

inline int SegTree_askrank(int x, int y, int k, int now, int l, int r)
{
if(x <= l && r <= y) return Splay_findrank(now, k);
if(l > y || r < x) return 0;
int mid = (l + r) >> 1;
return SegTree_askrank(x, y, k, lson) + SegTree_askrank(x, y, k, rson);
}

inline void SegTree_change(int x, int k, int now, int l, int r)
{
Splay_find(now, seq[x]);
Splay_del(now);
Splay_insert(now, k);
if(l == r) return;
int mid = (l + r) >> 1;
if(x <= mid) SegTree_change(x, k, lson);
else SegTree_change(x, k, rson);
}

inline int SegTree_findpre(int x, int y, int k, int now, int l, int r)
{
if(x <= l && r <= y) return Splay_findpre(now, k);
if(l > y || r < x) return -INF;
int mid = (l + r) >> 1;
return max(SegTree_findpre(x, y, k, lson), SegTree_findpre(x, y, k, rson));
}

inline int SegTree_findsuc(int x, int y, int k, int now, int l, int r)
{
if(x <= l && r <= y) return Splay_findsuc(now, k);
if(l > y || r < x) return INF;
int mid = (l + r) >> 1;
return min(SegTree_findsuc(x, y, k, lson), SegTree_findsuc(x, y, k, rson));
}

int main()
{
int i, opt, x, y, z, ans, h, t, mid, maxn = 0;
n = read();
m = read();
for(i = 1; i <= n; i++) seq[i] = read(), maxn = max(maxn, seq[i]), SegTree_insert(i, seq[i], root);
for(i = 1; i <= m; i++)
{
opt = read();
switch(opt)
{
case 1:
{
x = read();
y = read();
z = read();
printf("%d\n", SegTree_askrank(x, y, z, root) + 1);
break;
}
case 2:
{
x = read();
y = read();
z = read();
h = 0, t = maxn;
while(h <= t)
{
mid = (h + t) >> 1;
if(SegTree_askrank(x, y, mid, root) + 1 <= z) h = mid + 1;
else ans = mid, t = mid - 1;
}
printf("%d\n", ans - 1);
break;
}
case 3:
{
x = read();
z = read();
SegTree_change(x, z, root);
seq[x] = z;
maxn = max(maxn, z);
break;
}
case 4:
{
x = read();
y = read();
z = read();
printf("%d\n", SegTree_findpre(x, y, z, root));
break;
}
case 5:
{
x = read();
y = read();
z = read();
printf("%d\n", SegTree_findsuc(x, y, z, root));
break;
}
}
}
return 0;
}
View Code

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: