bzoj1758 [Wc2010]重建计划 & bzoj2599 [IOI2011]Race
两题都是树分治。
1758这题可以二分答案avgvalue,因为avgvalue=Σv(e)/s,因此二分后只需要判断Σv(e)-s*avgvalue是否大于等于0,若大于等于0则调整二分下界,否则调整二分上界。假设一棵树树根为x,要求就是经过树根x的最大答案,不经过树根x的可以递归求解。假设B[i]为当前做到的一颗x的子树中的点到x的距离为i的最大权值,A[i]为之前已经做过的所有子数中的点到x的距离为i的最大权值(这里的权值是Σv(e)-i*avgvalue),那么对于当前子树的一个距离i,可以从之前处理的子树中取到树根x距离为L-i到U-i权值中最大的那个,判断B[i]+max(A[L-i],A[U-i])是否大于等于0,这里max(A[L-i],A[U-i])可以用一个单调队列求,每处理完一颗子树用B数组更新A数组。
2599数据范围在讨论里,比较简单。
代码:
1 //bzoj1758 2 #include<cstdio> 3 #include<algorithm> 4 #include<map> 5 #include<cstring> 6 #include<vector> 7 #include<cmath> 8 #include<string> 9 #define N 500010 10 #define M 1010 11 using namespace std; 12 double ans,A[N],B[N],P; 13 int AS,BS; 14 int pre[N],p[N],tt[N],ww[N],dp,n,L,U,a,b,c,father[N],s[N],flag[N],tmproot,i,j,l,r,f[N]; 15 double left,right,mid; 16 void link(int x,int y,int z) 17 { 18 dp++;pre[dp]=p[x];p[x]=dp;tt[dp]=y;ww[dp]=z; 19 } 20 void getroot(int x,int fa,int sum) 21 { 22 int i,f=0; 23 i=p[x]; 24 father[x]=fa; 25 s[x]=1; 26 while (i) 27 { 28 if ((tt[i]!=fa)&&(!flag[tt[i]])) 29 { 30 getroot(tt[i],x,sum); 31 s[x]=s[x]+s[tt[i]]; 32 if (s[tt[i]]>sum/2) f=1; 33 } 34 i=pre[i]; 35 } 36 if (sum-s[x]>sum/2) f=1; 37 if (f==0) tmproot=x; 38 } 39 void dfs(int x,int fa,int deep,double value) 40 { 41 int i; 42 i=p[x]; 43 B[deep]=max(B[deep],value-mid*double(deep)); 44 BS=max(deep,BS); 45 while (i) 46 { 47 if ((tt[i]!=fa)&&(!flag[tt[i]])) 48 dfs(tt[i],x,deep+1,value+ww[i]); 49 i=pre[i]; 50 } 51 } 52 void work(int x,int sum) 53 { 54 int i,root,ti,ff; 55 getroot(x,0,sum); 56 root=tmproot; 57 flag[root]=1; 58 i=p[root]; 59 while (i) 60 { 61 if (!flag[tt[i]]) 62 { 63 if (father[root]!=tt[i]) 64 work(tt[i],s[tt[i]]); 65 else 66 work(tt[i],sum-s[root]); 67 } 68 i=pre[i]; 69 } 70 //---------------------------------- 71 left=0;right=1000000;ti=0; 72 while (ti<=35) 73 { 74 ti++; 75 mid=(left+right)/2; 76 ff=0; 77 for (i=1;i<=AS;i++) 78 A[i]=P;AS=0; 79 i=p[root]; 80 while (i) 81 { 82 if (!flag[tt[i]]) 83 { 84 for (j=1;j<=BS;j++) 85 B[j]=P;BS=0; 86 dfs(tt[i],0,1,ww[i]); 87 r=0;l=1; 88 for (j=min(U-1,AS);j>=L;j--) 89 { 90 r++;f[r]=j; 91 while ((l<r)&&(A[f[r]]>=A[f[r-1]])) 92 { 93 f[r-1]=f[r]; 94 r--; 95 } 96 } 97 for (j=1;j<=BS;j++) 98 { 99 100 if ((L<=j)&&(j<=U)) 101 if (B[j]>=0) ff=1; 102 103 while ((l<=r)&&(f[l]+j>U)) l++; 104 if (L-j>0) 105 { 106 r++;f[r]=L-j; 107 while ((l<r)&&(A[f[r]]>=A[f[r-1]])) 108 { 109 f[r-1]=f[r]; 110 r--; 111 } 112 if (A[f[l]]+B[j]>=0) ff=1; 113 } 114 } 115 for (j=1;j<=BS;j++) 116 A[j]=max(A[j],B[j]); 117 AS=max(AS,BS); 118 } 119 if (ff) break; 120 i=pre[i]; 121 } 122 123 if (ff) left=mid;else right=mid; 124 } 125 ans=max(ans,left); 126 flag[root]=0; 127 } 128 int main() 129 { 130 scanf("%d",&n); 131 scanf("%d%d",&L,&U); 132 P=1000000; 133 P=-P*P; 134 for (i=1;i<=n-1;i++) 135 { 136 scanf("%d%d%d",&a,&b,&c); 137 link(a,b,c); 138 link(b,a,c); 139 } 140 for (i=1;i<=n;i++) 141 { 142 A[i]=P; 143 B[i]=P; 144 } 145 ans=0; 146 work(1,n); 147 printf("%.3lf",ans); 148 }
1 //bzoj2599 2 #include<cstdio> 3 #include<algorithm> 4 #include<map> 5 #include<cstring> 6 #include<vector> 7 #include<cmath> 8 #include<string> 9 #define N 1000010 10 #define M 1010 11 #define P 1000000007 12 using namespace std; 13 int i,j,p[N],tt[N],s[N],father[N],ww[N],pre[N],tmproot,n,m; 14 int dp,flag[N],a,b,c,f[N],g[N],AS,BS,A[N],B[N],ans; 15 void link(int x,int y,int z) 16 { 17 dp++;pre[dp]=p[x];p[x]=dp;tt[dp]=y;ww[dp]=z; 18 } 19 void getroot(int x,int fa,int sum) 20 { 21 int i,f=0; 22 i=p[x]; 23 father[x]=fa; 24 s[x]=1; 25 while (i) 26 { 27 if ((tt[i]!=fa)&&(!flag[tt[i]])) 28 { 29 getroot(tt[i],x,sum); 30 s[x]=s[x]+s[tt[i]]; 31 if (s[tt[i]]>sum/2) f=1; 32 } 33 i=pre[i]; 34 } 35 if (sum-s[x]>sum/2) f=1; 36 if (f==0) tmproot=x; 37 } 38 void dist(int x,int fa,int deep,int value) 39 { 40 int i; 41 i=p[x]; 42 if (value<=m) 43 { 44 if (g[value]==0x37373737) 45 { 46 BS++; 47 B[BS]=value; 48 } 49 g[value]=min(g[value],deep); 50 } 51 else 52 return; 53 while (i) 54 { 55 if ((tt[i]!=fa)&&(!flag[tt[i]])) 56 dist(tt[i],x,deep+1,value+ww[i]); 57 i=pre[i]; 58 } 59 60 } 61 void work(int x,int sum) 62 { 63 int i,root; 64 getroot(x,0,sum); 65 root=tmproot; 66 flag[root]=1; 67 i=p[root]; 68 while (i) 69 { 70 if (!flag[tt[i]]) 71 { 72 if (tt[i]==father[root]) 73 work(tt[i],sum-s[root]); 74 else 75 work(tt[i],s[tt[i]]); 76 } 77 i=pre[i]; 78 } 79 //----------------------------- 80 for (i=1;i<=AS;i++) 81 f[A[i]]=0x37373737;AS=0; 82 i=p[root]; 83 while (i) 84 { 85 if (!flag[tt[i]]) 86 { 87 for (j=1;j<=BS;j++) 88 g[B[j]]=0x37373737;BS=0; 89 dist(tt[i],0,1,ww[i]); 90 for (j=1;j<=BS;j++) 91 ans=min(ans,g[B[j]]+f[m-B[j]]); 92 for (j=1;j<=BS;j++) 93 if (f[B[j]]==0x37373737) 94 { 95 AS++;A[AS]=B[j]; 96 } 97 for (j=1;j<=BS;j++) 98 f[B[j]]=min(f[B[j]],g[B[j]]); 99 } 100 i=pre[i]; 101 } 102 flag[root]=0; 103 } 104 int main() 105 { 106 scanf("%d%d",&n,&m); 107 for (i=1;i<=n-1;i++) 108 { 109 scanf("%d%d%d",&a,&b,&c); 110 a++;b++; 111 link(a,b,c); 112 link(b,a,c); 113 } 114 for (i=1;i<=m;i++) 115 { 116 f[i]=0x37373737; 117 g[i]=f[i]; 118 } 119 ans=0x37373737; 120 work(1,n); 121 if (ans!=0x37373737) 122 printf("%d",ans); 123 else 124 printf("-1"); 125 }