1208: [HNOI2004]宠物收养所

容器splay。
考察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;

#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;

#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;
}







Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐