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


    点分治,对于每个分治中心,考虑求出经过它的符合长度条件的链的最大权值和。

    从分治中心dfs下去取出所有链,为了防止两条链属于同一个子树,我们一个子树一个子树地处理。

    用s1[i]记录目前分治中心伸下去的链中长度为i的链的最大权值,s2[i]记录新子树中的链的最大权值。

    分数规划,考虑合并,枚举长度,由于另一个长度在一个滑动窗口中,所以使用单调队列求解即可。

    为了保证复杂度,讲子树按高度排序。注意初始化等问题。

     1 #include<cstdio>
     2 #include<vector>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
     6 using namespace std;
     7 
     8 const int N=200010;
     9 const double eps=1e-8,inf=1e9;
    10 bool vis[N];
    11 int n,L,R,u,v,w,S,rt,tot,sz[N],f[N],he[N],d[N],q[N];
    12 int cnt,h[N],pre[N],to[N<<1],val[N<<1],nxt[N<<1];
    13 double ans,dis[N],s1[N],s2[N];
    14 vector<int>ve;
    15 void add(int u,int v,int w){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; }
    16 
    17 bool cmp(int a,int b){ return he[a]<he[b]; }
    18 
    19 void get(int x,int fa){
    20     sz[x]=1; f[x]=0;
    21     For(i,x) if ((k=to[i])!=fa && !vis[k])
    22         get(k,x),f[x]=max(f[x],sz[k]),sz[x]+=sz[k];
    23     f[x]=max(f[x],S-sz[x]);
    24     if (f[x]<f[rt]) rt=x;
    25 }
    26 
    27 void dfs(int x,int fa){
    28     d[x]=d[fa]+1; he[x]=1;
    29     For(i,x) if ((k=to[i])!=fa && !vis[k])
    30         pre[k]=val[i],dfs(k,x),he[x]=max(he[x],he[k]+1);
    31 }
    32 
    33 void dfs2(int x,int fa,double mid){
    34     dis[x]=dis[fa]+pre[x]-mid; s2[d[x]]=max(s2[d[x]],dis[x]);
    35     For(i,x) if ((k=to[i])!=fa && !vis[k]) dfs2(k,x,mid);
    36 }
    37 
    38 bool jud(double mid){
    39     double res=-inf;
    40     rep(i,0,tot){
    41         int k=ve[i],st=1,ed=0; dis[rt]=0;
    42         rep(j,1,he[k]) s2[j]=-inf; dfs2(k,rt,mid);
    43         rep(j,0,he[k]){
    44             if (st<=ed && q[st]>R-j) st++;
    45             if (L-j<=he[k]){
    46                 while (st<=ed && s1[q[ed]]<s1[L-j]) ed--;
    47                 q[++ed]=L-j;
    48             }
    49             if (st<=ed) res=max(res,s1[q[st]]+s2[j]);
    50         }
    51         rep(j,1,he[k]) s1[j]=max(s1[j],s2[j]);
    52     }
    53     return res>0;
    54 }
    55 
    56 void solve(int x){
    57     vis[x]=1; d[0]=-1; dfs(x,0); dis[x]=0; ve.clear();
    58     For(i,x) if (!vis[k=to[i]]) ve.push_back(k=to[i]);
    59     tot=ve.size()-1;
    60     if (tot==-1) return;
    61     sort(ve.begin(),ve.end(),cmp);
    62     int ed=he[ve[tot]];
    63     double L=ans,R=1e6;
    64     while (L+eps<R){
    65         double mid=(L+R)/2;
    66         rep(i,1,ed) s1[i]=-inf; s1[0]=0;
    67         if (jud(mid)) L=mid; else R=mid;
    68     }
    69     ans=max(ans,L);
    70     For(i,x) if (!vis[k=to[i]]) rt=0,S=sz[k],get(k,x),solve(rt);
    71 }
    72 
    73 int main(){
    74     freopen("bzoj1758.in","r",stdin);
    75     freopen("bzoj1758.out","w",stdout);
    76     scanf("%d%d%d",&n,&L,&R);
    77     rep(i,2,n) scanf("%d%d%d",&u,&v,&w),add(u,v,w),add(v,u,w);
    78     f[0]=n+1; S=n; rt=0; get(1,0);
    79     solve(rt); printf("%.3lf
    ",ans);
    80     return 0;
    81 }
  • 相关阅读:
    docker--docker介绍
    docker--虚拟化
    高级运维工程师的打怪升级之路
    mysql常用函数
    CentOS 7 下使用 Firewall
    51nod 1094 和为k的连续区间(map+前缀和)
    51nod 1092 回文字符串(dp)
    51nod 1062 序列中最大的数(打表预处理)
    51nod 1284 2 3 5 7的倍数(容斥原理+反面思考)
    51nod 1347 旋转字符串(思维好题)
  • 原文地址:https://www.cnblogs.com/HocRiser/p/10176130.html
Copyright © 2020-2023  润新知