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

Posted Kaiser

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1758 [Wc2010]重建计划 分数规划+树分治单调队列check相关的知识,希望对你有一定的参考价值。

[Wc2010]重建计划

Time Limit: 40 Sec  Memory Limit: 162 MB
Submit: 4345  Solved: 1054
[Submit][Status][Discuss]

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<=U<=N-1,Vi<=1000000 新加数据一组 By leoly,但未重测..2016.9.27

 

题解:点分上是一个log,二分是一个log,然后是单调队列判断,n,总复杂度O(nlogn^2)

hzwer的代码十分不优秀,应该是按照最低深度从小到大去个棵子树去判断才可以,不然是不行的,

不然会是复杂度退化成n^2

 

改了比较siz还是T,不知道为什么了。

  1 #include<cstring>
  2 #include<cmath>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<cstdio>
  6 #include<cstdlib>
  7 #include<vector>
  8 
  9 #define inf 1000000007
 10 #define eps 0.0001
 11 #define N 100007
 12 #define M 200007
 13 #define ll long long
 14 using namespace std;
 15 inline int read()
 16 {
 17     int x=0,f=1;char ch=getchar();
 18     while(ch<0||ch>9){if (ch==-) f=-1;ch=getchar();}
 19     while(ch>=0&&ch<=9){x=(x<<3)+(x<<1)+ch-0;ch=getchar();}
 20     return x*f;
 21 }
 22 
 23 int n,S,L,U,rt,lim;
 24 double ans;
 25 int cnt,hed[N],rea[M],val[M],nxt[M];
 26 int sz[N],fa[N],f[N],dep[N];
 27 int q[N],dq[N];
 28 bool flag[N];
 29 double dis[N],mx[N];
 30 int num[N*10],xz,shu[N*10];
 31 
 32 void add(int u,int v,int w)
 33 {
 34     nxt[++cnt]=hed[u];
 35     hed[u]=cnt;
 36     rea[cnt]=v;
 37     val[cnt]=w;
 38 }
 39 void get_root(int u,int fa)
 40 {
 41     sz[u]=1,f[u]=0;
 42     for (int i=hed[u];i!=-1;i=nxt[i])
 43     {
 44         int v=rea[i];
 45         if (v==fa||flag[v]) continue;
 46         get_root(v,u);
 47         sz[u]+=sz[v];
 48         f[u]=max(f[u],sz[v]);
 49     }
 50     f[u]=max(f[u],S-sz[u]);
 51     if (f[u]<=f[rt])rt=u;
 52 }
 53 bool check(int rt,double zhi)
 54 {
 55     int up=0;
 56     for (int i=hed[rt];i!=-1;i=nxt[i])
 57     {
 58         int v=rea[i];double fee=(double)val[i]-zhi;
 59         if (flag[v])continue;
 60         int hd=0,tl=1;
 61         q[0]=v;
 62         fa[v]=rt,dep[v]=1;
 63         dis[v]=fee;
 64         while(hd!=tl)
 65         {
 66             int now=q[hd];hd++;
 67             for (int i=hed[now];i!=-1;i=nxt[i])
 68             {
 69                 int v=rea[i];double fee=(double)val[i]-zhi;
 70                 if (v==fa[now]||flag[v])continue;
 71                 q[tl++]=v;
 72                 fa[v]=now,dep[v]=dep[now]+1;
 73                 dis[v]=dis[now]+fee;
 74             }
 75         }
 76         int l=1,r=0,now=up;
 77         for (int i=0;i<tl;i++)
 78         {
 79             int x=q[i];
 80             while(dep[x]+now>=L&&now>=0)
 81             {
 82                 while(l<=r&&mx[dq[r]]<mx[now])r--;
 83                 dq[++r]=now;
 84                 now--;
 85             }
 86             while(l<=r&&dep[x]+dq[l]>U)l++;
 87             if (l<=r&&dis[x]+mx[dq[l]]>=0)return 1;
 88         }
 89         for (int i=up+1;i<=dep[q[tl-1]];i++)mx[i]=-inf;
 90         for (int i=0;i<tl;i++)
 91         {
 92             int x=q[i];
 93             mx[dep[x]]=max(mx[dep[x]],dis[x]);
 94         }
 95         up=max(up,dep[q[tl-1]]);
 96     }
 97     return 0;
 98 }
 99 void cal(int u)//可以
100 {
101     double l=ans,r=lim,mid;
102     while(r-l>eps)
103     {
104         mid=(l+r)/2;
105         if(check(u,mid))l=mid;
106         else r=mid;
107     }
108     ans=l;    
109 }
110 bool cmp(int x,int y)
111 {
112     return shu[x]<shu[y];
113 }
114 void solve(int u)
115 {
116     cal(u);
117     flag[u]=1;int yl=xz,Sum=S;
118     for (int i=hed[u];i!=-1;i=nxt[i])
119     {
120         int v=rea[i];
121         if (flag[v])continue;
122         rt=0;
123         if (sz[v]<sz[u])S=sz[v];
124         else S=Sum-sz[u];
125         get_root(v,0);
126         if(sz[v]>L)num[++xz]=rt,shu[++xz]=S;
127     }
128     sort(num+yl+1,num+xz+1,cmp);
129     for (int i=yl+1;i<=xz;i++)
130         solve(num[i]);
131     xz=yl;
132 }
133 int main()
134 {
135     memset(hed,-1,sizeof(hed));
136     n=read(),L=read(),U=read();
137     for (int i=1;i<n;i++)
138     {
139         int u=read(),v=read(),w=read();
140         add(u,v,w),add(v,u,w);
141         lim=max(lim,w);
142     }
143     f[0]=n;
144     rt=0,S=n;
145     get_root(1,0);
146     solve(rt);
147     printf("%.3lf",ans);
148 }

 

以上是关于bzoj 1758 [Wc2010]重建计划 分数规划+树分治单调队列check的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1758 [Wc2010]重建计划

bzoj1758 [Wc2010]重建计划

bzoj1758[Wc2010]重建计划

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

bzoj1758Wc10重建计划——solution

[WC2010]重建计划(分数规划+点分治+单调队列)