ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[COI2009] OTOCI

2022-02-26 09:32:35  阅读:152  来源: 互联网

标签:OTOCI ch int void COI2009 Splay inline 节点


link

一道比LCT模板还要模板的模板(它甚至没有cut操作),主要借此题来阐述几个代码上的细节。

第一个是makelink函数。以下写法上对下错:

inline void makelink(int x,int y){
	makeroot(x);
	if(findroot(y)^x)t[x].f=y;
}

inline void makelink(int x,int y){
	makeroot(x);
	if(findroot(y)^x)t[y].f=x;
}

回答这个问题要回到LCT最基本的定义上来。LCT维护了一大堆的Splay,每一个Splay中的节点都会有一个父亲(根节点所在Splay的根除外),这父亲有两种情况,一种是Splay上的边,描述了一条实链的情况;另一种是树上的虚边,具体表现方式是这个Splay(也就是这条实链)的根有一个父亲,可怜的是父亲的左右孩子都不是它,这条链记录了这条实链中最浅节点在原树中的父亲。

总结一下,假如你要给一个Splay的根赋值父亲,就相当于给这棵Splay中最左边节点(原树中该实链最上面的节点)和某个节点连边。一定注意,这个活动的等效物是在原树中该实链最浅节点上连边,而非Splay根节点在原树中对应节点连边,一定要注意。所以要给一个根一个父亲,首先要保证它没有左孩子,这样才能做到所做即所得。

反应到代码中,由于x已经被makeroot了,可以保证它是它所在Splay中最浅的节点(这不废话吗),所以把x的fa设置为y是合理的,相反由于无法保证y是实链中最高的节点,所以把y的fa赋值为x是不合理的。所以才有了那样的写法。引以为戒。

另外一个就是rotate函数里一定要保证2+4的修改,即6组父子关系一定要弄到位。

#include<cstdio>
#define zczc
const int N=30010;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
    wh*=f;return;
}
inline void swap(int &s1,int &s2){
	int s3=s1;s1=s2;s2=s3;return;
}

int m,n;
#define lc t[x].ch[0]
#define rc t[x].ch[1]
struct node{
	int f,ch[2],data,sum;
	bool lazy;
}t[N];
inline void pushdown(int x){
	if(!t[x].lazy)return;t[x].lazy=false;
	t[lc].lazy^=1,t[rc].lazy^=1,swap(lc,rc);
}
inline void pushup(int x){
	t[x].sum=t[lc].sum+t[rc].sum+t[x].data;
}
inline bool check(int x){
	int fa=t[x].f;
	return t[fa].ch[0]==x||t[fa].ch[1]==x;
}
inline void rotate(int x){
	int y=t[x].f;int z=t[y].f;bool kk=t[y].ch[1]==x;
	if(check(y))t[z].ch[t[z].ch[1]==y]=x;
	if(t[x].ch[!kk])t[t[x].ch[!kk]].f=y;
	t[x].f=z;t[y].f=x;t[y].ch[kk]=t[x].ch[!kk];t[x].ch[!kk]=y;
	pushup(y);pushup(x);return;
}
inline void pushdd(int x){
	if(check(x))pushdd(t[x].f);
	pushdown(x);
}
inline void splay(int x){
	pushdd(x);
	while(check(x)){
		int y=t[x].f;int z=t[y].f;
		if(check(y))(t[z].ch[1]==y)^(t[y].ch[1]==x)?rotate(x):rotate(y);
		rotate(x);
	}
}
inline void access(int x){
	for(int y=0;x;x=t[y=x].f){
		splay(x);rc=y;
		if(y)t[y].f=x;
		pushup(x);
	}
}
inline void makeroot(int x){
	access(x);splay(x);
	t[x].lazy^=1;
}
inline int findroot(int x){
	access(x);splay(x);
	while(t[x].ch[0])pushdown(x),x=lc;
	return x;
}
inline void change(int x,int val){
	access(x);splay(x);
	t[x].data=val;pushup(x);
}
inline void makelink(int x,int y){
	makeroot(x);
	if(findroot(y)^x){printf("yes\n");t[x].f=y;}
	else printf("no\n");
}
inline void work(int x,int y){
	makeroot(x);
	if(findroot(y)^x)printf("impossible\n");
	else printf("%d\n",t[y].sum);
}

#undef lc
#undef rc

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);char w[20];int s1,s2;
	for(int i=1;i<=m;i++){
		read(s1);t[i].data=t[i].sum=s1;
	}
	read(n);
	for(int tt=1;tt<=n;tt++){
		scanf("%s",w);read(s1);read(s2);
		switch(w[0]){
			case 'b':makelink(s1,s2);break;
			case 'p':change(s1,s2);break;
			case 'e':work(s1,s2);break;
		}
	}
	
	return 0;
}

标签:OTOCI,ch,int,void,COI2009,Splay,inline,节点
来源: https://www.cnblogs.com/dai-se-can-tian/p/15938512.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有