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 } 
时间: 2024-10-14 11:57:05

bzoj1758 [Wc2010]重建计划 & bzoj2599 [IOI2011]Race的相关文章

bzoj1758 [Wc2010]重建计划

Description Input 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai,Bi,Vi分别表示道路(Ai,Bi),其价值为Vi 其中城市由1..N进行标号 Output 输出最大平均估值,保留三位小数 Sample Input 4 2 3 1 2 1 1 3 2 1 4 3 Sample Output 2.500 HINT N<=100000,1<=L

BZOJ1758: [Wc2010]重建计划(01分数规划+点分治+单调队列)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1758 01分数规划,所以我们对每个重心进行二分.于是问题转化为Σw[e]-mid>=0, 对于一棵子树维护点的dep,dis,并用队列q存下来.令mx[i]表示当前dep为i的最大权值,维护一个单调队列dq,维护当前符合条件的mx,当我们从q的队尾向前扫时,它的dep是递减的,利用这个性质维护单调队列,最后更新一遍mx.具体看代码吧TAT 代码: #include<cstring>#

【BZOJ 1758】 [Wc2010]重建计划

1758: [Wc2010]重建计划 Time Limit: 40 Sec  Memory Limit: 162 MB Submit: 989  Solved: 345 [Submit][Status] Description Input 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai,Bi,Vi分别表示道路(Ai,Bi),其价值为Vi 其中城市由1..N进行标

bzoj 1758 [Wc2010]重建计划 分数规划+树分治单调队列check

[Wc2010]重建计划 Time Limit: 40 Sec  Memory Limit: 162 MBSubmit: 4345  Solved: 1054[Submit][Status][Discuss] Description Input 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai,Bi,Vi分别表示道路(Ai,Bi),其价值为Vi 其中城市由1..N

【bzoj1758】[Wc2010]重建计划

Description Input 第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai,Bi,Vi分别表示道路(Ai,Bi),其价值为Vi 其中城市由1..N进行标号 Output 输出最大平均估值,保留三位小数 Sample Input 4 2 3 1 2 1 1 3 2 1 4 3 Sample Output 2.500 HINT N<=100000,1<=L

[BZOJ]1758: [Wc2010]重建计划

题目大意:给定一棵n个点的带边权的树和l,u,求长度在[l,u]之间平均权值最大的链的权值.(n<=100,000) 思路:二分答案,把树上每条边减去二分出的答案,点分治check是否有长度在[l,u]之间权值和大等0的链,每次把每棵子树按深度排序,记下各个深度到根距离最大的节点,再用单调队列统计即可,总复杂度O(nlogn^2).此题卡常差评,重心只要算一次,不用每次二分都算,稍微卡卡就过了. #include<cstdio> #include<cstring> #incl

【点分治】【哈希表】bzoj2599 [IOI2011]Race

给nlog2n随便过的跪了,不得已弄了个哈希表伪装成nlogn(当然随便卡,好孩子不要学)…… 不过为啥哈希表的大小开小点就RE啊……?必须得超过数据范围一大截才行……谜 #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int f,c; inline void R(int &x){ c=0;f=1; for(;c<'0'||c>'9';c=getc

bzoj2599: [IOI2011]Race(点分治)

写了四五道点分治的题目了,算是比较理解点分治是什么东西了吧= = 点分治主要用来解决点对之间的问题的,比如距离为不大于K的点有多少对. 这道题要求距离等于K的点对中连接两点的最小边数. 那么其实道理是一样的.先找重心,然后先从重心开始求距离dis和边数num,更新ans,再从重心的儿子开始求得dis和num,减去这部分答案 因为这部分的答案中,从重心开始的两条链有重叠部分,所以要剪掉 基本算是模板题,但是减去儿子的答案的那部分还有双指针那里调了好久,所以还不算特别熟练.. PS跑了27秒慢到飞起

[BZOJ2599][IOI2011]Race

试题描述 给一棵树,每条边有权.求一条简单路径,权值和等于K,且边的数量最小.N <= 200000, K <= 1000000 输入 第一行 两个整数 n, k第二..n行 每行三个整数 表示一条无向边的两端和权值 (注意点的编号从0开始) 输出 一个整数 表示最小边数量 如果不存在这样的路径 输出-1 输入示例 4 3 0 1 1 1 2 2 1 3 4 输出示例 2 数据规模及约定 见“试题描述” 题解 点分治裸题.我还调了半天TAT...好久没写什么都忘了... 每次找子树的中心往下递