[SDOI2011]染色
Description给定一棵有n个节点的无根树和m个操作,操作有2类:1、将节点a到节点b路径上所有点都染成颜色c;2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。请你写一个程序依次完成这m个操作。Input第一行包含2个整数n和m,分别表示节点数和操作数;第二行包含n个正整数表示n个节点的初始颜色下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。下面 行每行描述一个操作:“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。Output对于每个询问操作,输出一行答案。Sample Input6 52 2 1 2 1 11 21 32 42 52 6Q 3 5C 2 1 1Q 3 5C 5 1 2Q 3 5Sample Output312HINT数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。分析:
树链剖分后用线段树维护数据,还是比较好的一道题。
树链剖分的第一个dfs要求出各个点的深度d,父节点fa,子树节点数sz,重儿子son,第二个dfs求出每个点在序列中的位置id,所在路径顶端节点编号top。
第二个dfs就是用来剖分路径的,要注意必须先对重儿子处理,只有这样一条路径的点在序列上才是连续的,这样才能用线段树维护。
然后就是线段树维护了, 不要忘记修改x到y的权值要用id[x]和id[y]表示,另外注意任何对线段树的操作必须先下传懒惰标记。
在查询时由于要跨过多条路径,相邻两个路径相接的地方颜色相同的情况也要判断。
代码:
program putcolor;type thing=record l,r,v,s,e:longint; end; point=^node; node=record x:longint; next:point; end;var a:array[0..100000]of point; dat:array[0..400000]of thing; sz,son,id,fa,v,b,d,top:array[0..100000]of longint; n,i,m,len:longint;procedure add(x,y:longint);var p:point;begin new(p); p^.x:=y; p^.next:=a[x]; a[x]:=p;end;procedure swap(var x,y:longint);var t:longint;begin t:=x; x:=y; y:=t;end;procedure dfs1(x:longint);var y:longint; p:point;begin new(p); p:=a[x]; sz[x]:=1; while p<>nil do begin if p^.x=fa[x] then begin p:=p^.next; continue; end; y:=p^.x; fa[y]:=x; d[y]:=d[x]+1; dfs1(y); inc(sz[x],sz[y]); if sz[y]>sz[son[x]] then son[x]:=y; p:=p^.next; end;end;procedure dfs2(x,k:longint);var i:longint; p:point;begin inc(len); id[x]:=len; b[len]:=v[x]; top[x]:=k; if son[x]>0 then dfs2(son[x],k); new(p); p:=a[x]; while p<>nil do begin if (p^.x<>fa[x])and(p^.x<>son[x]) then dfs2(p^.x,p^.x); p:=p^.next; end;end;procedure down(p,x,y:longint);var l,r,v:longint;begin if x=y then exit; l:=p*2; r:=p*2+1; v:=dat[p].e; dat[l].l:=v; dat[l].r:=v; dat[l].s:=1;dat[l].e:=v; dat[r].l:=v; dat[r].r:=v; dat[r].s:=1;dat[r].e:=v; dat[p].e:=-1;end;procedure update(p,x,y:longint);var l,r:longint;begin if x=y then exit; l:=p*2; r:=p*2+1; dat[p].l:=dat[l].l; dat[p].r:=dat[r].r; dat[p].s:=dat[l].s+dat[r].s; if dat[l].r=dat[r].l then dec(dat[p].s);end;procedure build(p,l,r:longint);var mid:longint;begin dat[p].s:=0; dat[p].e:=-1; if l=r then exit; mid:=(l+r) div 2; build(p*2,l,mid); build(p*2+1,mid+1,r);end;procedure change(x,y,p,l,r,v:longint);var mid:longint;begin if dat[p].e>=0 then down(p,l,r); if (x<=l)and(r<=y) then begin dat[p].l:=v; dat[p].r:=v; dat[p].s:=1; dat[p].e:=v; end else begin mid:=(l+r) div 2; if x<=mid then change(x,y,p*2,l,mid,v); if y>mid then change(x,y,p*2+1,mid+1,r,v); update(p,l,r); end;end;function query(x,y,p,l,r:longint):longint;var mid,ans:longint;begin if (x<=l)and(r<=y) then exit(dat[p].s) else begin mid:=(l+r) div 2;if dat[p].e>=0 then down(p,l,r); ans:=0; if x<=mid then ans:=query(x,y,p*2,l,mid); if y>mid then inc(ans,query(x,y,p*2+1,mid+1,r)); if (x<=mid)and(y>mid) then if dat[p*2].r=dat[p*2+1].l then dec(ans); exit(ans); end;end;function get(p,l,r,x:longint):longint;var mid:longint;begin if dat[p].e>=0 then down(p,l,r); if l=x then exit(dat[p].l); mid:=(l+r) div 2; if x<=mid then exit(get(p*2,l,mid,x)); if x>mid then exit(get(p*2+1,mid+1,r,x));end;procedure solvechange(x,y,z:longint);var fx,fy,t,ans:longint;begin fx:=top[x]; fy:=top[y]; ans:=0; while fx<>fy do begin if d[fx]d[y] then swap(x,y); change(id[x],id[y],1,1,n,z);end;function solvequery(x,y:longint):longint;var fx,fy,t,ans:longint;begin fx:=top[x]; fy:=top[y]; ans:=0; while fx<>fy do begin if d[fx] d[y] then swap(x,y); inc(ans,query(id[x],id[y],1,1,n)); exit(ans);end;procedure solve;var i,x,y,z:longint; c:char;begin build(1,1,n); for i:=1 to n do change(id[i],id[i],1,1,n,v[i]); for i:=1 to m do begin read(c); if c='C' then begin read(x,y,z); solvechange(x,y,z); end else begin read(x,y); writeln(solvequery(x,y)); end; readln; end;end;procedure int;var i,x,y:longint; p:point;begin readln(n,m); for i:=1 to n do read(v[i]); for i:=1 to n-1 do begin readln(x,y); add(x,y); add(y,x); end;end;begin int; dfs1(1);dfs2(1,1); solve;end.