【SDOI2011】染色(树链剖分或者动态树)

树链剖分与Splay树解题

【题目大意】:

给定一棵N颗节点无根树,每个结点有个颜色;以及M个操作:

C X Y Z 把X到Y的路径全染成Z颜色

Q X Y    询问X到Y的路径有多少个颜色段

【题目分析】:

1、树链剖分,线段树维护两端颜色及颜色段数;

2、动态树,Splay维护两段颜色及颜色段数;

在AndyBear的鼓舞下我使用Link—Cut—Tree AC了此题。(膜拜自顶而下的Splay)

PS:一个Splay里面的小Bug卡了我老半天……~~~~(>_<)~~~~

【附代码如下】:

Const
	maxn=100000;
Type
	link=^node;
	node=record
		id:longint;
		next:link;
	end;
Var
	q,f,l,r,lc,rc,d,c,rev:array[0..maxn]of longint;
	tp:array[0..maxn]of boolean;
	ee:array[0..maxn*2]of node;
	e:array[0..maxn]of link;
	ne,n,m,x,y,z,i:longint; o:char;
Procedure Swap(var a,b:boolean);
	var t:boolean;
	begin
		t:=a; a:=b; b:=t;
	end;
Procedure Update(x:longint);
	begin
		if l[x]<>0 then lc[x]:=lc[l[x]] else lc[x]:=c[x];
		if r[x]<>0 then rc[x]:=rc[r[x]] else rc[x]:=c[x];
		d[x]:=d[l[x]]+d[r[x]]+1-ord(c[x]=rc[l[x]])-ord(c[x]=lc[r[x]]);
	end;
Procedure Zig(x:longint);
	var y:longint;
	begin
		y:=f[x]; f[x]:=f[y]; Swap(tp[x],tp[y]);
		if y=l[f[y]] then l[f[y]]:=x else
		if y=r[f[y]] then r[f[y]]:=x;
		l[y]:=r[x]; if r[x]<>0 then f[r[x]]:=y;
		r[x]:=y; f[y]:=x;
		Update(x); Update(y);
	end;
Procedure Zag(x:longint);
	var y:longint;
	begin
		y:=f[x]; f[x]:=f[y]; Swap(tp[x],tp[y]);
		if y=l[f[y]] then l[f[y]]:=x else
		if y=r[f[y]] then r[f[y]]:=x;
		r[y]:=l[x]; if l[x]<>0 then f[l[x]]:=y;
		l[x]:=y; f[y]:=x;
		Update(x); Update(y);
	end;
Procedure Modify(x,k:longint);
	begin
		if x=0 then exit;
		lc[x]:=k; rc[x]:=k; c[x]:=k; d[x]:=1; rev[x]:=k;
	end;
Procedure Spread(x:longint);
	begin
		if rev[x]>0 then begin
			Modify(l[x],rev[x]);
			Modify(r[x],rev[x]);
			rev[x]:=0;
		end;
	end;
Procedure Splay(x,fa:longint);
	var y:longint;
	begin
		Spread(x);
		while (f[x]<>fa) and (not tp[x]) do begin
			y:=f[x];
			if (not tp[y]) and (f[y]<>0) then Spread(f[y]);
			Spread(y); Spread(x);
			if tp[y] or (f[y]=fa) then begin
				if x=l[y] then Zig(x) else Zag(x); break;
			end;
			if x=l[y] then begin
				if y=l[f[y]] then begin Zig(y); Zig(x); end else begin Zig(x); Zag(x); end;
			end else begin
				if y=r[f[y]] then begin Zag(y); Zag(x); end else begin Zag(x); Zig(x); end;
			end;
		end;
	end;
Procedure Color(x,y,k:longint);
	var i:longint;
	begin
		i:=0;
		while x<>0 do begin
			Splay(x,0);
			tp[r[x]]:=true; tp[x]:=true;
			r[x]:=i; tp[i]:=false; f[i]:=x;
			Update(x);
			i:=x; x:=f[x];
		end;
		i:=0;
		while y<>0 do begin
			Splay(y,0);
			if f[y]=0 then begin
				c[y]:=k; Modify(r[y],k); Modify(i,k); Update(y);
			end;
			tp[r[y]]:=true; tp[y]:=true;
			r[y]:=i; tp[i]:=false; f[i]:=y;
			Update(y);
			i:=y; y:=f[y];
		end;
	end;
Function Query(x,y:longint):longint;
	var i:longint;
	begin
		i:=0;
		while x<>0 do begin
			Splay(x,0);
			tp[r[x]]:=true; tp[x]:=true;
			r[x]:=i; tp[i]:=false; f[i]:=x;
			Update(x);
			i:=x; x:=f[x];
		end;
		i:=0;
		while y<>0 do begin
			Splay(y,0);
			if f[y]=0 then begin
				Query:=d[i]+d[r[y]]+1-ord(c[y]=lc[r[y]])-ord(c[y]=lc[i]);
			end;
			tp[r[y]]:=true; tp[y]:=true;
			r[y]:=i; tp[i]:=false; f[i]:=y;
			Update(y);
			i:=y; y:=f[y];
		end;
		writeln(Query);
	end;
Procedure Add(x,y:longint);
	var p:link;
	begin
		inc(ne); p:=@ee[ne]; p^.id:=y; p^.next:=e[x]; e[x]:=p;
	end;
Procedure Bfs;
	var h,t:longint; p:link;
	begin
		h:=0; t:=1; q[1]:=1;
		while h<t do begin
			inc(h); p:=e[q[h]];
			while p<>nil do with p^ do begin
				if f[q[h]]<>id then begin
					inc(t); q[t]:=id; f[id]:=q[h];
				end;
				p:=next;
			end;
		end;
	end;
Begin
	Assign(input,'paint.in'); reset(input);
	Assign(output,'paint.out'); rewrite(output);
	readln(n,m);
	for i:=1 to n do begin
		read(c[i]); d[i]:=1; lc[i]:=c[i]; rc[i]:=c[i]; rev[i]:=0; tp[i]:=true;
	end;
	for i:=1 to n-1 do begin
		readln(x,y); if x<>y then begin add(x,y); add(y,x); end;
	end;
	Bfs;
	for i:=1 to m do begin
		read(o);
		case o of
			'C':begin
					readln(x,y,z); Color(x,y,z);
				end;
			'Q':begin
					readln(x,y); Query(x,y);
				end;
		end;
	end;
	Close(input); Close(output);
End.

转载于:https://www.cnblogs.com/Skywalker-Q/archive/2011/05/13/2045808.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值