• [BZOJ4825][HNOI2017]单旋spaly


    BZOJ
    Luogu
    题目太长了,就不放了。

    题解

    首先声明一点,无论是splay还是spaly,插入一个新的元素,都要rotate到根!所以说题目也算是给了一个错误示范吧。
    我们发现把最值旋转到根并不会给这棵spaly造成多大的形态改变,所以考虑用LCT维护这个spaly的形态。
    每次插入的时候我们用一个Set来找出插入元素的前驱后继。可以证明,一定会插在前驱或者是后继的对应左右儿子上。判断一下插入即可。除了LCT里的splay外,还要维护一下原树中(spaly中)的父亲、左右儿子关系。

    code

    细节。。还好吧
    我tm又双叒叕把一个l打成r了

    #include<cstdio>
    #include<algorithm>
    #include<map>
    #include<set>
    using namespace std;
    const int N = 100005;
    int fa[N],ls[N],rs[N],rev[N],sz[N],Stack[N],top;
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    bool isroot(int x){return ls[fa[x]]!=x&&rs[fa[x]]!=x;}
    void pushup(int x){sz[x]=sz[ls[x]]+sz[rs[x]]+1;}
    void pushdown(int x){if (!rev[x]) return;swap(ls[x],rs[x]);rev[ls[x]]^=1;rev[rs[x]]^=1;rev[x]=0;}
    void R_rotate(int x)
    {
    	int y=fa[x],z=fa[y];
    	ls[y]=rs[x];
    	if (rs[x]) fa[rs[x]]=y;
    	fa[x]=z;
    	if (!isroot(y)) if (y==ls[z]) ls[z]=x;else rs[z]=x;
    	rs[x]=y;fa[y]=x;
    	pushup(y);
    }
    void L_rotate(int x)
    {
    	int y=fa[x],z=fa[y];
    	rs[y]=ls[x];
    	if (ls[x]) fa[ls[x]]=y;
    	fa[x]=z;
    	if (!isroot(y)) if (y==ls[z]) ls[z]=x;else rs[z]=x;
    	ls[x]=y;fa[y]=x;
    	pushup(y);
    }
    void splay(int x)
    {
    	Stack[top=1]=x;
    	for (int i=x;!isroot(i);i=fa[i])
    		Stack[++top]=fa[i];
    	while (top) pushdown(Stack[top--]);
    	while (!isroot(x))
    	{
    		int y=fa[x],z=fa[y];
    		if (isroot(y))
    			if (x==ls[y]) R_rotate(x);
    			else L_rotate(x);
    		else
    			if (y==ls[z])
    				if (x==ls[y]) R_rotate(y),R_rotate(x);
    				else L_rotate(x),R_rotate(x);
    			else
    				if (x==ls[y]) R_rotate(x),L_rotate(x);
    				else L_rotate(y),L_rotate(x);
    	}
    	pushup(x);
    }
    void access(int x){for (int y=0;x;y=x,x=fa[x]) splay(x),rs[x]=y,pushup(x);}
    void makeroot(int x){access(x);splay(x);rev[x]^=1;}
    void split(int x,int y){makeroot(x);access(y);splay(y);}
    void link(int x,int y){makeroot(x);fa[x]=y;}
    void cut(int x,int y){split(x,y);fa[x]=ls[y]=0;}
    map<int,int>M;
    set<int>S;
    int m,tot,root,ff[N],lson[N],rson[N];
    void Insert(int x)
    {
    	int now=++tot;
    	M[x]=now;
    	if (S.empty())
    	{
    		S.insert(x);
    		root=now;
    		puts("1");
    		return;
    	}
    	set<int>::iterator t=S.upper_bound(x);
    	if (t==S.end()||lson[M[*t]])
    	{
    		--t;
    		int father=M[*t];
    		link(now,father);rson[father]=now;ff[now]=father;
    	}
    	else
    	{
    		int father=M[*t];
    		link(now,father);lson[father]=now;ff[now]=father;
    	}
    	S.insert(x);
    	split(now,root);
    	printf("%d
    ",sz[root]);
    }
    void Spl_Min()
    {
    	int x=M[*S.begin()];
    	if (x==root) {puts("1");return;}
    	split(x,root);printf("%d
    ",sz[root]);
    	cut(x,ff[x]);if (rson[x]) cut(x,rson[x]);
    	link(x,root);if (rson[x]) link(ff[x],rson[x]);
    	lson[ff[x]]=rson[x];if (rson[x]) ff[rson[x]]=ff[x];
    	ff[x]=0;ff[root]=x;rson[x]=root;
    	root=x;
    }
    void Spl_Max()
    {
    	int x=M[*--S.end()];
    	if (x==root) {puts("1");return;}
    	split(x,root);printf("%d
    ",sz[root]);
    	cut(x,ff[x]);if (lson[x]) cut(x,lson[x]);
    	link(x,root);if (lson[x]) link(ff[x],lson[x]);
    	rson[ff[x]]=lson[x];if (lson[x]) ff[lson[x]]=ff[x];
    	ff[x]=0;ff[root]=x;lson[x]=root;
    	root=x;
    }
    void Del_Min()
    {
    	int x=M[*S.begin()];
    	if (x==root)
    	{
    		puts("1");
    		if (rson[x]) cut(x,rson[x]);
    		ff[root=rson[x]]=0;
    		S.erase(S.begin());
    		return;
    	}
    	split(x,root);printf("%d
    ",sz[root]);
    	cut(x,ff[x]);if (rson[x]) cut(x,rson[x]);
    	if (rson[x]) link(ff[x],rson[x]);
    	lson[ff[x]]=rson[x];if (rson[x]) ff[rson[x]]=ff[x];
    	S.erase(S.begin());
    }
    void Del_Max()
    {
    	int x=M[*--S.end()];
    	if (x==root)
    	{
    		puts("1");
    		if (lson[x]) cut(x,lson[x]);
    		ff[root=lson[x]]=0;
    		S.erase(--S.end());
    		return;
    	}
    	split(x,root);printf("%d
    ",sz[root]);
    	cut(x,ff[x]);if (lson[x]) cut(x,lson[x]);
    	if (lson[x]) link(ff[x],lson[x]);
    	rson[ff[x]]=lson[x];if (lson[x]) ff[lson[x]]=ff[x];
    	S.erase(--S.end());
    }
    int main()
    {
    	m=gi();
    	while (m--)
    	{
    		int opt=gi();
    		if (opt==1) Insert(gi());
    		if (opt==2) Spl_Min();
    		if (opt==3) Spl_Max();
    		if (opt==4) Del_Min();
    		if (opt==5) Del_Max();
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Android Activity 四种启动模式
    Android Activity的生命周期
    Android SQLite (五 ) 全面详解(三)
    Android SQLite (四 ) 全面详解(二)
    工作流设计 zt
    法律网站分类 ­zt
    刑事案件的构成要素 zt
    犯罪构成三层次记忆口诀 zt
    E asy Boo t 6.51 启动易 制作启动光盘的软件(附注册码)
    父线程开启子进程且共享内存
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8149091.html
Copyright © 2020-2023  润新知