题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4010
题意:一棵树,四种操作:
(1)若x和y不在一棵树上,将x和y连边;
(2)若x和y在一棵树上,将x变成树根,将y从x树上分离;
(3)若x和y在一棵树上,将x到y路径上的所有值增加det;
(4)若x和y在一棵树上,输出x到y路径上的最大值。
思路:一、由于出现的多棵树,那么每次操作之前都要判断询问的两个节点是不是在一棵树上,比如对于操作(2)(3)(4)来说都要保证x和y在一棵树上时操作才是合法的;对于(1)则x和y不能在一棵树上。首先,我们用一个函数makeroot(x)表示将x设为x所在树(是树而不是树链)的根。其实就是将x到其所在树的树根的路径上的边全部反向,那么x就会成为根。我们先access(x),那么x就与root连在一起,然后splay(x),x就调整到了根的位置,但是还不是跟,因为root现在其实在x的左孩子或者左孩子的子孙,x的右孩子现在为null,因为我们access(x)的时候将x与其右孩子断开了;那么现在我们将x的左孩子和右孩子互换(其实就是将右孩子设为左孩子,左孩子设为null),那么此时x就成为了真正的树根;
二、有了makeroot(x)之后,我们怎么判断x和y是不是在一个树上呢?首先makeroot(x),x成为树根;x的父节点为null。接着access(y),splay(y),试想,若x和y不在一棵树上,那么此时y的操作与x无任何关系,此时x的父节点还是null;但是,y若与x在一棵树上就不同了,现在y成了树根(只是调整到了树根的位置,x才是真正的树根),那么x必然是y的左孩子或者左孩子的子孙,即x的父节点不为空。据此,我们根据x的父节点是不是为null可判断x和y是否在一棵树上;其实用makeroot(y)代替access(y),splay(y)也是可以的,不好的地方就是这样就改变了树的真实结构;
三、现在我们说说对于题目中的四个操作怎么做:
(1)makeroot(x),access(y),splay(y),x和y若不在一棵树上,此时x的父节点为null,因此直接将x的父节点设为y;
(2)makeroot(x),access(y),splay(y),x和y若在一棵树上,y的右孩子实际是y的子孙,加上y也就是y所在子树,y的左孩子是y的祖宗节点,因此将y的左孩子置为null,同时将y左孩子的父节点置为null。
(3)(4)差不多,增加标志就可以。
struct node { int det,val,Max,isReversed; node *c[2],*f; void add(int x) { val+=x; det+=x; Max+=x; } void reverse() { isReversed^=1; swap(c[0],c[1]); } }; node a[N],*nullNode; int n; void pushUp(node *p) { p->Max=max(p->val,max(p->c[0]->Max,p->c[1]->Max)); } void pushDown(node *p) { if(p->det) { if(p->c[0]!=nullNode) p->c[0]->add(p->det); if(p->c[1]!=nullNode) p->c[1]->add(p->det); p->det=0; } if(p->isReversed) { if(p->c[0]!=nullNode) p->c[0]->reverse(); if(p->c[1]!=nullNode) p->c[1]->reverse(); p->isReversed=0; } } void rotate(node *p,int k) { node *q=p->f; q->c[k]=p->c[!k]; if(p->c[!k]!=nullNode) p->c[!k]->f=q; p->c[!k]=q; p->f=q->f; if(q->f!=nullNode) { if(p->f->c[0]==q) p->f->c[0]=p; if(p->f->c[1]==q) p->f->c[1]=p; } q->f=p; pushUp(q); } int isRoot(node *p) { return p->f==nullNode||p->f->c[0]!=p&&p->f->c[1]!=p; } void splay(node *p) { pushDown(p); while (!isRoot(p)) { if(isRoot(p->f)) { pushDown(p->f); pushDown(p); if(p==p->f->c[0]) rotate(p,0); else rotate(p,1); } else { pushDown(p->f->f); pushDown(p->f); pushDown(p); if(p->f->f->c[0]==p->f) { if(p->f->c[0]==p) rotate(p->f,0); else rotate(p,1); rotate(p,0); } else { if(p->f->c[1]==p) rotate(p->f,1); else rotate(p,0); rotate(p,1); } } } pushUp(p); } node* access(node *p) { node *q=nullNode; while(p!=nullNode) { splay(p); p->c[1]=q; pushUp(p); q=p; p=p->f; } return q; } void makeRoot(int x) { access(a+x); splay(a+x); a[x].reverse(); } void join(int x,int y) { if(x==y) { puts("-1"); return; } makeRoot(x);access(a+y);splay(a+y); if(a[x].f==nullNode) a[x].f=a+y; else puts("-1"); } void cut(int x,int y) { makeRoot(x);access(a+y);splay(a+y); if(a[x].f==nullNode) puts("-1"); else { a[y].c[0]->f=nullNode; a[y].c[0]=nullNode; pushUp(a+y); } } void change(int x,int y,int val) { makeRoot(y);access(a+x);splay(a+x); if(a[y].f==nullNode) { puts("-1"); return; } access(a+x); node *lca=access(a+y); if(lca->c[1]!=nullNode) lca->c[1]->add(val); lca->val+=val; if(a+x!=lca&&(a+x)!=nullNode) splay(a+x),a[x].add(val); pushUp(lca); } int query(int x,int y) { if(x==y) return a[x].val; makeRoot(y);access(a+x);splay(a+x); if(a[y].f==nullNode) return -1; access(a+x); node *lca=access(a+y); int ans; if(a+x!=nullNode) splay(a+x); if(a+x!=lca) { ans=max(lca->c[1]->Max,a[x].Max); ans=max(ans,lca->val); } else { ans=max(lca->c[1]->Max,lca->val); } return ans; } struct Node { int v,next; }; Node edges[N]; int head[N],e; void Add(int u,int v) { edges[e].v=v; edges[e].next=head[u]; head[u]=e++; edges[e].v=u; edges[e].next=head[v]; head[v]=e++; } void build() { queue<int> Q; Q.push(1); int i,u,v; while(!Q.empty()) { u=Q.front(); Q.pop(); for(i=head[u];i!=-1;i=edges[i].next) { v=edges[i].v; if(a+v==a[u].f) continue; a[v].f=a+u; Q.push(v); } } } int get() { int x=0,flag=1; char c=getchar(); while(!isdigit(c)) c=getchar(); if(c=='-') { flag=-1,c=getchar(); while(!isdigit(c)) c=getchar(); } while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } return x*flag; } void init() { nullNode=new node(); nullNode->isReversed=0; nullNode->det=0; nullNode->Max=-INF; nullNode->val=-INF; nullNode->c[0]=nullNode->c[1]=nullNode->f=nullNode; int i,u,v,dis; clr(head,-1); e=0; FOR1(i,n-1) u=get(),v=get(),Add(u,v); FOR1(i,n) { dis=get(); a[i].c[0]=a[i].c[1]=a[i].f=nullNode; a[i].isReversed=0; a[i].det=0; a[i].Max=a[i].val=dis; } build(); } int main() { while(scanf("%d",&n)!=-1) { init(); int a,b,c,op,m=get(); while(m--) { op=get(); if(op==1) a=get(),b=get(),join(a,b); else if(op==2) a=get(),b=get(),cut(a,b); else if(op==3) c=get(),a=get(),b=get(),change(a,b,c); else a=get(),b=get(),PR(query(a,b)); } puts(""); } return 0; }