BZOI splay 基础题目
1208: [HNOI2004]宠物收养所容器splay。考察splay对点的操作。查找:查找值为x的点所在的位置。插入:插入值为x的点(各点值唯一)。首先查找树中刚好比要插入的点小(或大)的点的位置,然后将x作为该点的子节点。插入后将x旋转到根。删除:删除值为x的点所在的位置。首先把x旋转到根,再把x的前驱结点旋转到x的左儿子,然后把x的前驱作为根,x的儿子连到新根上,删除x
·
1208: [HNOI2004]宠物收养所
容器splay。
考察splay对点的操作。
查找:查找值为x的点所在的位置。
插入:插入值为x的点(各点值唯一)。首先查找树中刚好比要插入的点小(或大)的点的位置,然后将x作为该点的子节点。插入后将x旋转到根。
删除:删除值为x的点所在的位置。首先把x旋转到根,再把x的前驱结点旋转到x的左儿子,然后把x的前驱作为根,x的儿子连到新根上,删除x。
(在某一时刻,要么全是宠物,要么全是人。如果新来的x,其种类与树中相同或树为空,执行插入操作。否则找到最接近x的点然后将其删除。)
考察splay对点的操作。
查找:查找值为x的点所在的位置。
插入:插入值为x的点(各点值唯一)。首先查找树中刚好比要插入的点小(或大)的点的位置,然后将x作为该点的子节点。插入后将x旋转到根。
删除:删除值为x的点所在的位置。首先把x旋转到根,再把x的前驱结点旋转到x的左儿子,然后把x的前驱作为根,x的儿子连到新根上,删除x。
(在某一时刻,要么全是宠物,要么全是人。如果新来的x,其种类与树中相同或树为空,执行插入操作。否则找到最接近x的点然后将其删除。)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
using namespace std;
const int Mn = 80000 + 10;
int son[Mn][2],fa[Mn],key[Mn],tot;
int size,root,flag;
int n,ans;
inline void rotate(int x,int y)
{
if(!fa[x]) return;
int p = fa[x];
// son
son[p][!y] = son[x][y];
fa[son[x][y]] = p;
// grand
fa[x] = fa[p];
if(son[fa[x]][0] == p) son[fa[x]][0] = x;
else son[fa[x]][1] = x;
// fa
son[x][y] = p;
fa[p] = x;
}
inline void splay(int x, int s)
{
while(fa[x] != s)
{
int p = fa[x];
if(x == son[p][0])
{
if(fa[p] != s && p == son[fa[p]][0])rotate(p,1); //注意 fa[p] != s 否则可能转过头
rotate(x,1);
}
else
{
if(fa[p] != s && p == son[fa[p]][1])rotate(p,0);
rotate(x,0);
}
}
if(!s)root = x;
}
inline int get_max(int s)
{
while(son[s][1])s=son[s][1];
return s;
}
inline int get_min(int s)
{
while(son[s][0])s=son[s][0];
return s;
}
inline int get_pre(int x)
{
splay(x,0);
if(son[x][0])
return get_max(son[x][0]);
return 0;
}
inline int get_nxt(int x)
{
splay(x,0);
if(son[x][1])
return get_min(son[x][1]);
return 0;
}
inline int find(int x,int s)
{
while(s && key[s] != x)
{
if(x < key[s])s = son[s][0];
else s = son[s][1];
}
if(s) splay(s,0);
return s;
}
inline void insert(int x)
{
int i=root,j=root;
while(j)
{
i = j;
if(x < key[j])j=son[j][0];
else j = son[j][1];
}
tot++;
size++;
key[tot] = x;
if(x < key[i])son[i][0] = tot;
else son[i][1] = tot;
fa[tot] = i;
splay(tot,0);
}
inline void del(int x)
{
splay(x,0);
if(son[x][0])
{
splay(get_max(son[x][0]),x);
root = son[x][0];
fa[root] = 0;
son[root][1] = son[x][1];
fa[son[x][1]] = root;
}
else
{
root = son[x][1];
fa[root] = 0;
}
size--;
}
int main()
{
scanf("%d",&n);
while(n--)
{
int x,y;
scanf("%d%d",&x,&y);
if(!size || flag == x)
insert(y),flag = x;
else
{
int pos = find(y,root);
if(!pos)
{
insert(y);
pos = tot;
int pre = get_pre(pos);
int nxt = get_nxt(pos);
int k1 = pre != 0 ? y - key[pre] : 0x7fffffff;
int k2 = nxt != 0 ? key[nxt] - y : 0x7fffffff;
if(k1 <= k2)
{
ans = (ans + k1)%1000000;
del(pre);
}
else
{
ans = (ans + k2)%1000000;
del(nxt);
}
}
del(pos);
}
}
cout<<ans;
}
1269: [AHOI2006]文本编辑器editor
要求模拟一个文本编辑器及其光标。
利用splay维护整个字符串的顺序(中序遍历就是原文本),加速操作。
维护size域来得到每个节点的rank;
注意:
增加保护节点;
MOVE:直接getrank;
INSERT:直接在光标后一个一个加入节点;
DELETE:区间删除 l-1转到根,r+1转到根的右儿子,然后删除r+1的左子树;
ROTATE:延迟标记,注意凡是改变树的结构都要自底向上pushup,凡是访问新的节点都要pushdown;
利用splay维护整个字符串的顺序(中序遍历就是原文本),加速操作。
维护size域来得到每个节点的rank;
注意:
增加保护节点;
MOVE:直接getrank;
INSERT:直接在光标后一个一个加入节点;
DELETE:区间删除 l-1转到根,r+1转到根的右儿子,然后删除r+1的左子树;
ROTATE:延迟标记,注意凡是改变树的结构都要自底向上pushup,凡是访问新的节点都要pushdown;
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace std;
const int Mn = 3 * 1024 * 1024 + 10;
char key[Mn],str[Mn];
int ch[Mn][2],fa[Mn],rev[Mn],root,tot,size[Mn];
int pos;
int n;
void rotate(int,int);
void splay(int,int);
void insert(char,int);
void del(int,int);
void pushup(int);
void pushdown(int);
int build(int,int);
int get_rank(int,int);
void MOVE();
void INSERT();
void DELETE();
void ROTATE();
void GET();
void PREV();
void NEXT();
inline void pushup(int x)
{size[x] = size[ch[x][0]] + size[ch[x][1]] + 1;}
inline void pushdown(int x)
{
if(rev[x]&1)
{
rev[ch[x][0]]^=1;
rev[ch[x][1]]^=1;
rev[x] = 0;
swap(ch[x][0],ch[x][1]);
}
}
inline int get_rank(int x,int k)
{
pushdown(x);
if(k == size[ch[x][0]] + 1) return x;
else if(k <= size[ch[x][0]]) return get_rank(ch[x][0],k);
else return get_rank(ch[x][1],k-size[ch[x][0]]-1);
}
inline void rotate(int x,int y)
{
if(!fa[x])return;
int p = fa[x];
fa[ch[x][y]] = p;
ch[p][!y] = ch[x][y];
fa[x] = fa[p];
if(ch[fa[x]][0] == p) ch[fa[x]][0] = x;
else ch[fa[x]][1] = x;
fa[p] = x;
ch[x][y] = p;
pushup(p);
pushup(x);
}
inline void splay(int x,int y)
{
while(fa[x] != y)
{
int p = fa[x];
if(x == ch[p][0])
{
if(p == ch[fa[p]][0] && fa[p] != y) rotate(p,1);
rotate(x,1);
}
else
{
if(p == ch[fa[p]][1] && fa[p] != y) rotate(p,0);
rotate(x,0);
}
}
if(!y) root = x;
}
inline int build(int l, int r)
{
int mid = l+r>>1;
if(l < mid)
{
int k = build(l,mid-1);
fa[k] = mid;
ch[mid][0] = k;
}
if(r > mid)
{
int k = build(mid+1,r);
fa[k] = mid;
ch[mid][1] = k;
}
pushup(mid);
return mid;
}
inline void MOVE()
{
int k;
scanf("%d",&k);
pos = get_rank(root,k+1);
}
inline void INSERT()
{
int k;
scanf("%d",&k);
getchar();
gets(str);
int l = tot+1;
for(int i = 0; i < k; i++)
key[++tot] = str[i];
int rt = build(l,tot);
splay(pos,0);
l = get_rank(root,size[ch[pos][0]]+1);
int r = get_rank(root,size[ch[pos][0]]+2);
splay(l,0),splay(r,root);
pushdown(l);
pushdown(r);
fa[rt] = ch[root][1];
ch[ch[root][1]][0] = rt;
pushup(ch[root][1]);
pushup(root);
}
inline void GET()
{
splay(pos,0);
printf("%c\n",key[get_rank(root,size[ch[pos][0]]+2)]);
}
inline void PREV()
{
splay(pos,0);
pos = get_rank(root,size[ch[pos][0]]);
}
inline void NEXT()
{
splay(pos,0);
pos = get_rank(root,size[ch[pos][0]]+2);
}
inline void DELETE()
{
int k;
scanf("%d",&k);
splay(pos,0);
int l = get_rank(root,size[ch[pos][0]]+1);
int r = get_rank(root,size[ch[pos][0]]+k+2);
splay(l,0);
splay(r,root);
pushdown(l);pushdown(r);
fa[ch[r][0]] = 0;
ch[r][0] = 0;
pushup(r);pushup(l);
}
inline void ROTATE()
{
int k;
scanf("%d",&k);
splay(pos,0);
int rank = size[ch[pos][0]]+1;
int l = get_rank(root,rank);
int r = get_rank(root,rank+k+1);
splay(l,0);
splay(r,root);
pushdown(l);pushdown(r);
rev[ch[r][0]]++;
pos = get_rank(root,rank);
}
int main()
{
pos = 1;
tot+=2;
root = 1;
ch[1][1] = 2;
fa[2] = 1;
key[1] = key[2] = '@';
scanf("%d",&n);
while(n--)
{
char s[10];
scanf("%s",s);
if(s[0] == 'M') MOVE();
else if(s[0] == 'I') INSERT();
else if(s[0] == 'D') DELETE();
else if(s[0] == 'R') ROTATE();
else if(s[0] == 'G') GET();
else if(s[0] == 'P') PREV();
else NEXT();
}
return 0;
}
1500: [NOI2005]维修数列
比较综合的一道数列spaly;
注意:
1、维护size来得到rank;
2、维护sum来支持求和;
3、维护val,f(最大子序),lf(左端起最大子序)rf(右端起最大子序)来支持最大子序查询;
4、通过rev,dt两个延迟标记支持翻转和更改;
5、通过内存池来节省内存(注意delete时候清空节点信息);
6、保护节点和平衡建树;
7、还是要注意标记的pushdown和pushup;
注意:
1、维护size来得到rank;
2、维护sum来支持求和;
3、维护val,f(最大子序),lf(左端起最大子序)rf(右端起最大子序)来支持最大子序查询;
4、通过rev,dt两个延迟标记支持翻转和更改;
5、通过内存池来节省内存(注意delete时候清空节点信息);
6、保护节点和平衡建树;
7、还是要注意标记的pushdown和pushup;
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace std;
const int Mn = 500000 + 10;
int ch[Mn][2],fa[Mn];
int tot,root;
int val[Mn],sum[Mn],dt[Mn],rev[Mn],f[Mn],lf[Mn],rf[Mn],size[Mn];
bool lazy[Mn];
int stack[Mn],top;
int list[Mn],end;
int n,m;
inline void pushup(int x)
{
if(!x) return;
size[x] = size[ch[x][0]] + size[ch[x][1]] + 1;
sum[x] = sum[ch[x][0]] + sum[ch[x][1]] + val[x];
f[x] = max(max(f[ch[x][0]],f[ch[x][1]]),val[x]+max(0,lf[ch[x][1]])+max(0,rf[ch[x][0]]));
lf[x] = max(lf[ch[x][0]],max(sum[ch[x][0]] + val[x] + lf[ch[x][1]],sum[ch[x][0]]+val[x]));
rf[x] = max(rf[ch[x][1]],max(sum[ch[x][1]] + val[x] + rf[ch[x][0]],sum[ch[x][1]]+val[x]));
}
inline void renew(int x, int y)
{
if(!x) return;
val[x] = y;
lazy[x] = true;
dt[x] = y;
sum[x] = size[x] * y;
f[x] = lf[x] = rf[x] = max(sum[x],y);
}
inline void reverse(int x)
{
if(!x) return;
rev[x] ^= 1;
swap(ch[x][0],ch[x][1]);
swap(lf[x],rf[x]);
}
inline void pushdown(int x)
{
if(!x) return;
if(lazy[x])
{
lazy[x] = false;
renew(ch[x][0],dt[x]);
renew(ch[x][1],dt[x]);
}
if(rev[x]&1)
{
rev[x] = 0;
reverse(ch[x][0]);
reverse(ch[x][1]);
}
}
inline void rotate(int x,int y)
{
if(!fa[x]) return;
int p = fa[x];
fa[ch[x][y]] = p;
ch[p][!y] = ch[x][y];
fa[x] = fa[p];
if(ch[fa[x]][0] == p) ch[fa[x]][0] = x;
else ch[fa[x]][1] = x;
fa[p] = x;
ch[x][y] = p;
pushup(p);
pushup(x);
}
inline void splay(int x,int y)
{
while(fa[x] != y)
{
int p = fa[x];
if(x == ch[p][0])
{
if(fa[p] != y && p == ch[fa[p]][0])
rotate(p,1);
rotate(x,1);
}
else
{
if(fa[p] != y && p == ch[fa[p]][1])
rotate(p,0);
rotate(x,0);
}
}
if(!y) root = x;
}
inline void del(int x)
{
if(!x) return;
del(ch[x][0]);
stack[top++] = x;
del(ch[x][1]);
ch[x][0] = ch[x][1] = fa[x] = lazy[x] = rev[x] = 0;
}
inline int new_node()
{
if(!top) return ++tot;
return stack[--top];
}
inline int build(int l,int r)
{
int mid = l+r>>1;
int pos = list[mid];
if(mid > l)
{
int k = build(l,mid-1);
fa[k] = pos;
ch[pos][0] = k;
}
if(mid < r)
{
int k = build(mid+1,r);
fa[k] = pos;
ch[pos][1] = k;
}
pushup(pos);
return pos;
}
inline int get_rank(int x,int k)
{
pushdown(x);
if(k == size[ch[x][0]] + 1)return x;
else if(k <= size[ch[x][0]])return get_rank(ch[x][0],k);
else return get_rank(ch[x][1],k-size[ch[x][0]]-1);
}
void INSERT()
{
int pos,n;
end = 0;
scanf("%d%d",&pos,&n);
for(int i = 1; i <= n; i++)
{
int now = new_node();
list[++end] = now;
scanf("%d",&val[now]);
}
int k = build(1,end);
int ll = get_rank(root,pos+1);
int rr = get_rank(root,pos+2);
splay(ll,0);
splay(rr,ll);
fa[k] = rr;
ch[rr][0] = k;
pushup(rr);
pushup(ll);
}
void DELETE()
{
int pos,k;
scanf("%d%d",&pos,&k);
int ll = get_rank(root,pos);
int rr = get_rank(root,pos+1+k);
splay(ll,0),splay(rr,ll);
del(ch[rr][0]);
ch[rr][0] = 0;
pushup(rr);pushup(ll);
}
void MAKE_SAME()
{
int pos,k,c;
scanf("%d%d%d",&pos,&k,&c);
int ll = get_rank(root,pos);
int rr = get_rank(root,pos+1+k);
splay(ll,0);splay(rr,ll);
renew(ch[rr][0],c);
pushup(rr);pushup(ll);
}
void REVERSE()
{
int pos,k;
scanf("%d%d",&pos,&k);
int ll = get_rank(root,pos);
int rr = get_rank(root,pos+1+k);
splay(ll,0);splay(rr,ll);
reverse(ch[rr][0]);
pushup(rr);pushup(ll);
}
void GET_SUM()
{
int pos,k;
scanf("%d%d",&pos,&k);
splay(get_rank(root,pos),0);
splay(get_rank(root,pos+1+k),root);
printf("%d\n",sum[ch[ch[root][1]][0]]);
}
void MAX_SUM()
{
splay(get_rank(root,1),0);
splay(get_rank(root,size[root]),root);
printf("%d\n",f[ch[ch[root][1]][0]]);
}
int main()
{
val[0] = f[0] = lf[0] = rf[0] = 0xe9e9e9e9;
sum[0] = 0;
scanf("%d%d",&n,&m);
end = 0;
top = 0;
list[++end] = new_node();
for(int i = 1; i <= n; i++)
{
int pos = new_node();
list[++end] = pos;
scanf("%d",&val[pos]);
}
list[++end] = new_node();
root = build(1,end);
while(m--)
{
char s[10];
scanf("%s",s);
if(s[0] == 'I')INSERT();
else if(s[0] == 'D')DELETE();
else if(s[0] == 'M' && s[2] == 'K')MAKE_SAME();
else if(s[0] == 'R')REVERSE();
else if(s[0] == 'G')GET_SUM();
else MAX_SUM();
}
return 0;
}
2809: [Apio2012]dispatching
splay的启发式合并,其余都是基本操作;
注意:
1、防止爆栈要自底向上拓扑排序;
2、启发式合并要清空节点信息在接到新的位置;
3、longlong的问题;
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace std;
typedef long long lint;
const int Mn = 100000 + 10;
int hd[Mn],nxt[Mn],to[Mn],cnt;
int num[Mn],b[Mn],c[Mn],l[Mn];
int deg[Mn],stack[Mn],top;
int fa[Mn],ch[Mn][2],key[Mn],size[Mn];
int root,tot;
lint sum[Mn];
int n,m;
int que[Mn];
inline void pushup(int x)
{
size[x] = size[ch[x][0]] + size[ch[x][1]] + 1;
sum[x] = sum[ch[x][0]] + sum[ch[x][1]] + key[x];
}
inline void add(int x,int y)
{
to[cnt] = y;
nxt[cnt] = hd[x];
hd[x] = cnt++;
}
inline void rotate(int x, int y)
{
if(!fa[x]) return;
int p = fa[x];
fa[ch[x][y]] = p;
ch[p][!y] = ch[x][y];
fa[x] = fa[p];
if(ch[fa[x]][0] == p) ch[fa[x]][0] = x;
else ch[fa[x]][1] = x;
fa[p] = x;
ch[x][y] = p;
pushup(p);pushup(x);
}
inline int get_rank(int x,int k)
{
if(k == size[ch[x][0]] + 1)return x;
else if(k <= size[ch[x][0]])return get_rank(ch[x][0],k);
else return get_rank(ch[x][1],k-size[ch[x][0]]-1);
}
inline void splay(int x, int y)
{
if(!x) return ;
while(fa[x] != y)
{
int p = fa[x];
if(x == ch[p][0])
{
if(fa[p] != y && ch[fa[p]][0] == p) rotate(p,1);
rotate(x,1);
}
else
{
if(fa[p] != y && ch[fa[p]][1] == p) rotate(p,0);
rotate(x,0);
}
}
if(!y) root = x;
}
inline void insert(int x,int y)
{
int now = y,pre = y;
while(now)
{
pre = now;
if(key[x] < key[now]) now = ch[now][0];
else now = ch[now][1];
}
fa[x] = pre;
if(key[x] < key[pre])ch[pre][0] = x;
else ch[pre][1] = x;
while(x)pushup(x),x=fa[x];
splay(x,0);
}
inline void merge(int x,int y)
{
int big = x,small = y;
if(size[x] < size[y]) swap(big,small);
root = big;
int h = 1, t = 2;
que[1] = small;
while(h < t)
{
int sta = que[h++];
if(ch[sta][0]) que[t++] = ch[sta][0];
if(ch[sta][1]) que[t++] = ch[sta][1];
ch[sta][0] = ch[sta][1] = 0;
insert(sta,root);
}
splay(x,0);
}
inline int get_num(int x,int y)
{
if(!x) return 0;
if(y <= sum[ch[x][0]])return get_num(ch[x][0],y);
else if(y >= sum[ch[x][0]] + key[x]) return size[ch[x][0]] + 1 + get_num(ch[x][1],y-sum[ch[x][0]]-key[x]);
else return size[ch[x][0]];
}
inline lint get_ans(int x)
{
num[x] = ++tot;
key[tot] = c[x];
root = num[x];
pushup(tot);
for(int i = hd[x];~i; i = nxt[i])
merge(root,num[to[i]]);
int k = get_num(root,m);
splay(num[x],0);
return (lint)l[x]*k;
}
inline lint solve()
{
lint res(0x8000000000000000ll);
for(int i = 1; i <= n; i++)
if(!deg[i]) stack[top++] = i;
while(top)
{
int sta = stack[--top];
res = max(res,get_ans(sta));
deg[b[sta]]--;
if(!deg[b[sta]] && b[sta]) stack[top++] = b[sta];
}
return res;
}
int main()
{
memset(hd,-1,sizeof hd);
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
{
scanf("%d%d%d",&b[i],&c[i],&l[i]);
add(b[i],i);
deg[b[i]]++;
}
cout<<solve()<<endl;
return 0;
}
2733: [HNOI2012]永无乡
裸的启发式和并;
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
using namespace std;
typedef long long lint;
const int Mn = 100000 + 10;
int fa[Mn],ch[Mn][2],key[Mn],size[Mn];
int p[Mn],que[Mn];
int root,tot;
lint sum[Mn];
int n,m;
inline void pushup(int x)
{
size[x] = size[ch[x][0]] + size[ch[x][1]] + 1;
sum[x] = sum[ch[x][0]] + sum[ch[x][1]] + key[x];
}
inline void rotate(int x, int y)
{
if(!fa[x]) return;
int p = fa[x];
fa[ch[x][y]] = p;
ch[p][!y] = ch[x][y];
fa[x] = fa[p];
if(ch[fa[x]][0] == p) ch[fa[x]][0] = x;
else ch[fa[x]][1] = x;
fa[p] = x;
ch[x][y] = p;
pushup(p);pushup(x);
}
inline int get_rank(int x,int k)
{
if(k == size[ch[x][0]] + 1)return x;
else if(k <= size[ch[x][0]])return get_rank(ch[x][0],k);
else return get_rank(ch[x][1],k-size[ch[x][0]]-1);
}
inline void splay(int x, int y)
{
if(!x) return ;
while(fa[x] != y)
{
int p = fa[x];
if(x == ch[p][0])
{
if(fa[p] != y && ch[fa[p]][0] == p) rotate(p,1);
rotate(x,1);
}
else
{
if(fa[p] != y && ch[fa[p]][1] == p) rotate(p,0);
rotate(x,0);
}
}
if(!y) root = x;
}
inline void insert(int x,int y)
{
int now = y,pre = y;
while(now)
{
pre = now;
if(key[x] < key[now]) now = ch[now][0];
else now = ch[now][1];
}
fa[x] = pre;
if(key[x] < key[pre])ch[pre][0] = x;
else ch[pre][1] = x;
while(x)pushup(x),x=fa[x];
splay(x,0);
}
inline void merge(int x,int y)
{
int big = x,small = y;
if(size[x] < size[y]) swap(big,small);
root = big;
int h = 1, t = 2;
que[1] = small;
while(h < t)
{
int sta = que[h++];
if(ch[sta][0]) que[t++] = ch[sta][0];
if(ch[sta][1]) que[t++] = ch[sta][1];
ch[sta][0] = ch[sta][1] = 0;
insert(sta,root);
}
splay(x,0);
}
inline int find(int x)
{
return p[x] == x ? x : p[x] = find(p[x]);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
scanf("%d",&key[i]),p[i] = i,pushup(i);
for(int i = 1; i <= m; i++)
{
int x,y;
scanf("%d%d",&x,&y);
if(find(x) != find(y))
{
splay(x,0);
splay(y,0);
merge(x,y);
p[find(x)] = find(y);
}
}
int q;
scanf("%d",&q);
while(q--)
{
char s[10];
int x,y;
scanf("%s%d%d",s,&x,&y);
if(s[0] == 'B')
{
if(find(x) != find(y))
{
splay(x,0);
splay(y,0);
merge(x,y);
p[find(x)] = find(y);
}
}
else
{
splay(x,0);
int ans = get_rank(x,y);
printf("%d\n",ans ? ans : -1);
}
}
return 0;
}
更多推荐
已为社区贡献1条内容
所有评论(0)