题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2243
题意:一棵树,初始时每个节点有一个颜色。两种操作:(1)将某条路经上的点的颜色统一修改为某个值;(2)统计某条路径上颜色有多少段?比如11221算3段。
思路:splay节点记录区间的左右两侧的颜色LR,该节点的颜色val以及总的段数以及标记。向上合并时根据左孩子右孩子的LR以及当前节点的val计算当前子树的段数。修改时,[x,y],先access(x)使得x与lca在一起。然后从y向上,直到找到lca,y和lca的右子树标记修改,lca直接修改。这里要注意,lca的右子树和y要判断是不是为nullNode,在这里wa两个小时。。。统计答案时与修改类似。
struct node { int L,R,val,sum,flag; node *c[2],*p; void set(int color) { L=R=val=flag=color; sum=1; } }; node a[N],*nullNode; void pushUp(node *p) { if(p==nullNode) return; p->sum=1; p->L=p->R=p->val; if(p->c[0]!=nullNode) { if(p->c[0]->R==p->L) p->sum+=p->c[0]->sum-1; else p->sum+=p->c[0]->sum; p->L=p->c[0]->L; } if(p->c[1]!=nullNode) { if(p->c[1]->L==p->R) p->sum+=p->c[1]->sum-1; else p->sum+=p->c[1]->sum; p->R=p->c[1]->R; } } void pushDown(node *p) { if(p==nullNode) return; if(p->flag!=-1) { if(p->c[0]!=nullNode) p->c[0]->set(p->flag); if(p->c[1]!=nullNode) p->c[1]->set(p->flag); p->flag=-1; } } int isRoot(node *p) { return p->p==nullNode||p->p->c[0]!=p&&p->p->c[1]!=p; } node *zig(node *x) { node *p=x->p,*q=p->p; p->c[0]=x->c[1]; if(x->c[1]!=nullNode) x->c[1]->p=p; x->c[1]=p; p->p=x; x->p=q; if(q!=nullNode) { if(q->c[0]==p) q->c[0]=x; if(q->c[1]==p) q->c[1]=x; } pushUp(p); pushUp(x); } node *zag(node *x) { node *p=x->p,*q=p->p; p->c[1]=x->c[0]; if(x->c[0]!=nullNode) x->c[0]->p=p; x->c[0]=p; p->p=x; x->p=q; if(q!=nullNode) { if(q->c[0]==p) q->c[0]=x; if(q->c[1]==p) q->c[1]=x; } pushUp(p); pushUp(x); } void splay(node *x) { pushDown(x); while(!isRoot(x)) { if(!isRoot(x->p)) { pushDown(x->p->p); pushDown(x->p); pushDown(x); if(x->p->p->c[0]==x->p) { if(x->p->c[0]==x) zig(x->p),zig(x); else zag(x),zig(x); } else { if(x->p->c[1]==x) zag(x->p),zag(x); else zig(x),zag(x); } } else { pushDown(x->p); pushDown(x); if(x->p->c[0]==x) zig(x); else zag(x); } } } node *access(node *x) { node *p=nullNode; while(x!=nullNode) { splay(x); x->c[1]=p; pushUp(x); p=x; x=x->p; } return p; } int cal(int x,int y) { access(a+x); node *lca=access(a+y); splay(a+x); int ans; if(lca!=a+x) { ans=lca->c[1]->sum+a[x].sum+1; if(lca->c[1]->L==lca->val) ans--; if(a[x].L==lca->val) ans--; } else { ans=lca->c[1]->sum+1; if(lca->c[1]->L==lca->val) ans--; } return ans; } void color(int x,int y,int val) { access(a+x); node *lca=access(a+y); splay(a+x); if(a+x!=lca) { if(a+x!=nullNode) a[x].set(val); if(lca->c[1]!=nullNode) lca->c[1]->set(val); lca->val=val; } else { if(lca->c[1]!=nullNode) lca->c[1]->set(val); lca->val=val; } pushUp(lca); } vector<int> g[N]; int n,m,C[N]; void build() { queue<int> Q; Q.push(1); a[1].c[0]=a[1].c[1]=a[1].p=nullNode; a[1].L=a[1].R=a[1].val=C[1]; a[1].sum=1; a[1].flag=-1; int i,u,v; while(!Q.empty()) { u=Q.front(); Q.pop(); FOR0(i,SZ(g[u])) { v=g[u][i]; if(a+v==a[u].p) continue; a[v].p=a+u; a[v].c[0]=a[v].c[1]=nullNode; a[v].L=a[v].R=a[v].val=C[v]; a[v].sum=1; a[v].flag=-1; Q.push(v); } } } void init() { nullNode=new node(); nullNode->L=nullNode->R=nullNode->val=-2; nullNode->sum=0; nullNode->c[0]=nullNode->c[1]=nullNode->p=nullNode; RD(n,m); int i,x,y; FOR1(i,n) RD(C[i]); FOR1(i,n-1) { RD(x,y); g[x].pb(y); g[y].pb(x); } build(); } int main() { init(); char op[5]; int x,y,z; while(m--) { RD(op); if(op[0]=='Q') { RD(x,y); PR(cal(x,y)); } else { RD(x,y,z); color(x,y,z); } } }