动态树第一次攻关
动态树
动态的维护 树上的很多条链。这些链组成了这棵树。。
要熟练掌握splay splay 是为了快速的将这条链打通。
access 利用splay 完成打通路径。
还要理解 那些 链的性质
就差不多了。。。。
下面是 bzoj 2002 弹飞绵羊那道题的写法。。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int max_point=200005; struct str { int c[2];//0是左 int size; int pathparent; //实际的父节点 int p; // bool d; }e[max_point]; int n,m,temp,num,tot=0; void upd(int x) { e[x].size=e[e[x].c[1]].size+e[e[x].c[0]].size+1; } void sc(int x,int d,int y)//x的d孩子是y { e[x].c[d]=y; e[y].p=x; e[y].d=d; //e[y].pathparent=0; //y没有pathparent } void rot(int x) { int y=e[x].p; bool d=e[x].d; if(!e[y].p) //如果y没有父亲 { e[x].p=0; e[x].pathparent=e[y].pathparent; //表明把x旋转到根了。 e[y].pathparent=0; //*****这里必须要有。超时应该就是这里。 } else sc(e[y].p,e[y].d,x); sc(y,d,e[x].c[!d]); sc(x,!d,y); upd(y); } void splay(int x) { int p1,p2; while(p1=e[x].p) { if(p2=e[p1].p) //如果p1 有父节点 { if(e[x].d==e[p1].d) rot(p1),rot(x); else rot(x),rot(x); } else //如果p1没有父节点,只旋转1次 rot(x); } upd(x); } void access(int x) { int y=x; x=0; //起点的右孩子要断掉 while(y) //从当前点出发,将相应的pathparent修改好。 { splay(y); e[e[y].c[1]].pathparent=y; //把y的后继链断掉 e[e[y].c[1]].p=0; sc(y,1,x); //让y的右孩子是x e[x].pathparent=0; upd(y); x=y; y=e[y].pathparent; } } void search() { scanf("%d",&temp);temp+=1; access(temp); splay(temp); printf("%d\n",e[e[temp].c[0]].size); } void change() { scanf("%d%d",&temp,&num);temp+=1; access(temp); splay(temp); int son=e[temp].c[0]; e[son].p=0; sc(temp,0,0); //将temp的左子树剪掉 if(temp+num>n)num=n+1-temp; //将新边连上。 e[temp].pathparent=temp+num; upd(temp); } int main() { freopen("add.in","r",stdin); freopen("add.out","w",stdout); scanf("%d",&n); memset(e,0,sizeof(e)); e[n+1].size=1; for(int i=1;i<=n;i++) { scanf("%d",&temp); if(temp+i>n) e[i].pathparent=n+1; else e[i].pathparent=temp+i; e[i].size=1; } scanf("%d",&m); while(m--) { scanf("%d",&temp); if(temp==1) tot++,search(); else change(); } fclose(stdin);fclose(stdout); return 0; }

浙公网安备 33010602011771号