【BZOJ4472】salesman(树形DP)
题意:
给定一颗有点权的树,每个树上的节点最多能走到lim[u]次,求一条路径,使路径上的点权和最大,每个节点上的点权如果走了多次只能算一次。还要求方案是否唯一。
思路:每个点只能取lim[u]-1个子树。因为每个子树只取1次或不取,考虑树形DP,dp[u]=dp[v1]+dp[v2]+...(加lim[u]-1)个,是排序后最大的。因为不一定要去满lim[u]-1个,如果负数就不走。
判多解:
1.儿子不唯一老子不唯一。
2.取得最后一个和不取的第一个dp值相等就不唯一。
3.取得里面有0就不唯一。
1 var head,vet,next,lim:array[1..210000]of longint; 2 dp,c,d,f,a:array[1..210000]of int64; 3 n,m,i,x,y,tot:longint; 4 5 procedure add(a,b:longint); 6 begin 7 inc(tot); 8 next[tot]:=head[a]; 9 vet[tot]:=b; 10 head[a]:=tot; 11 end; 12 13 procedure swap(var x,y:int64); 14 var t:int64; 15 begin 16 t:=x; x:=y; y:=t; 17 end; 18 19 procedure qsort(l,r:longint); 20 var i,j:longint; 21 mid:int64; 22 begin 23 i:=l; j:=r; mid:=c[(l+r)>>1]; 24 repeat 25 while mid<c[i] do inc(i); 26 while mid>c[j] do dec(j); 27 if i<=j then 28 begin 29 swap(c[i],c[j]); swap(d[i],d[j]); 30 inc(i); dec(j); 31 end; 32 until i>j; 33 if l<j then qsort(l,j); 34 if i<r then qsort(i,r); 35 end; 36 37 38 procedure dfs(u,pre:longint); 39 var e,v,i,m,j:longint; 40 begin 41 e:=head[u]; m:=0; 42 while e<>0 do 43 begin 44 v:=vet[e]; 45 if v<>pre then dfs(v,u); 46 e:=next[e]; 47 end; 48 e:=head[u]; 49 while e<>0 do 50 begin 51 v:=vet[e]; 52 if v<>pre then begin inc(m); c[m]:=dp[v]; d[m]:=f[v]; end; 53 e:=next[e]; 54 end; 55 if m>0 then qsort(1,m); 56 dp[u]:=a[u]; 57 f[u]:=0; j:=0; 58 for i:=1 to m do 59 begin 60 if (i>lim[u]-1)or(c[i]<0) then break; 61 inc(j); 62 dp[u]:=dp[u]+c[i]; 63 if d[i]=1 then f[u]:=1; 64 if c[i]=0 then f[u]:=1; 65 end; 66 if (j>0)and(j+1<=m)and(c[j]=c[j+1]) then f[u]:=1; 67 for i:=1 to m do begin c[i]:=0; d[i]:=0; end; 68 end; 69 70 begin 71 72 readln(n); 73 for i:=2 to n do read(a[i]); 74 lim[1]:=n; 75 for i:=2 to n do read(lim[i]); 76 for i:=1 to n-1 do 77 begin 78 readln(x,y); 79 add(x,y); 80 add(y,x); 81 end; 82 dfs(1,0); 83 writeln(dp[1]); 84 if f[1]=0 then writeln('solution is unique') 85 else writeln('solution is not unique'); 86 87 end.
null