9
17
2013
0

【BZOJ3251】树上三角形【倍增】

显然我们要求出每个询问两个点的最近公共祖先。然后我们可以求出其最短路径上的点数。显然,如果要不能构成三角形,那么上面的点权一定是按照大于斐波那契数列排列的,这样在55项左右就超过MAXLONGINT。所以大于等于55一定构成三角形。余下的反正是有50+的点直接SORT一下然后暴力即可。PASCAL的代码又一次又臭又长,居然垫底了。。QAQ

program p3251;
	type
		bian=record
			next,point:int64;
		end;
		arr=array[0..500] of int64;
	var
		f:array[1..111111,0..17] of int64;
		w,d,p:array[1..111111] of int64;
		b:array[1..111111] of bian;
		way:arr;
		len,i,j,q,n,k1,k2,k3:longint;
		ch:char;
		pd:boolean;
	procedure add(k1,k2:int64);
		begin
			inc(len); 
			b[len].point:=k2;
			b[len].next:=p[k1];
			p[k1]:=len;
		end;
	procedure find(k1,k2:int64);
		var
			i,j:longint;
		begin
			d[k1]:=k2;
			i:=p[k1];
			while i<>0 do begin
				find(b[i].point,k2+1);
				i:=b[i].next;
			end;
		end;
	function go_up(k1,k2:int64):int64;
		var
			i,j,k:longint;
		begin
			if k2=0 then exit(k1);
			for k:=0 to 17 do
				if 1 shl k>k2 then break;
			dec(k);
			for i:=0 to k do 
				if k2 and (1 shl i)>0 then k1:=f[k1,i];
			exit(k1);
		end;
	procedure sort(var x:arr;first,en:longint);
		var
			i,j:longint;
		begin
			i:=first; j:=en; x[0]:=x[first];
			while i<j do begin
				while (i<j) and (w[x[j]]>=w[x[0]]) do dec(j);
				if i<j then x[i]:=x[j];
				while (i<j) and (w[x[i]]<w[x[0]]) do inc(i);
				if i<j then x[j]:=x[i];
			end;
			x[i]:=x[0];
			if i>first+1 then sort(x,first,i-1);
			if i<en-1 then sort(x,i+1,en);
		end;	
	function answer(k1,k2:int64):char;
		var
			k,i,j,k3,k4,k5,l:longint;
		begin
			if d[k1]>d[k2] then begin
				i:=k1; k1:=k2; k2:=i;
			end;
			k3:=go_up(k2,d[k2]-d[k1]);
			for k:=0 to 17 do
				if 1 shl k>=d[k3] then break;
			dec(k);
			k4:=k1;
			if k3<>k4 then begin
				for i:=k downto 0 do
					if f[k3,i]<>f[k4,i] then begin
						k3:=f[k3,i];
						k4:=f[k4,i];
					end;
				k3:=f[k3,0];
			end;
			l:=d[k1]-d[k3]+d[k2]-d[k3]+1;
			if (l<3) then exit('N');
			if (l>=55) then exit('Y');
			l:=0;
			i:=k1; 
			while i<>k3 do begin
				inc(l); way[l]:=i; i:=f[i,0];
			end;
			i:=k2; inc(l); way[l]:=i;
			while i<>k3 do begin
				i:=f[i,0]; inc(l); way[l]:=i;
			end;
			sort(way,1,l);
			for i:=3 to l do
				if w[way[i-2]]+w[way[i-1]]>w[way[i]] then exit('Y');
			exit('N');
		end;
	begin
		readln(n,q);
		len:=0;
		fillchar(p,sizeof(p),0);
		fillchar(b,sizeof(b),0);
		fillchar(f,sizeof(f),0);
		for i:=1 to n do
			read(w[i]);
		for i:=1 to n-1 do begin
			readln(k1,k2);
			f[k2,0]:=k1;
			add(k1,k2);
		end;
		find(1,1);
		for i:=1 to 17 do begin
			pd:=false;
			for j:=1 to n do
				if 1 shl i<d[j] then begin
					pd:=true;
					f[j,i]:=f[f[j,i-1],i-1];
				end;
			if pd=false then break;
		end;
		for i:=1 to q do begin
			readln(k1,k2,k3);
			if k1=0 then
				writeln(answer(k2,k3))
			else 
				w[k2]:=k3;
		end;
	end.
Category: 倍增 | Tags: | Read Count: 1757

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com