zoukankan      html  css  js  c++  java
  • [luogu7600]封闭道路

    对于确定的$K$,问题也可以看作每一个点最多选$K$条出边,并最大化选择的边权和

    关于这个问题,有如下的树形dp——

    令$f_{k,0/1}$表示以$k$为根的子树中,根节点选择不超过$K/K-1$个儿子的最大边权和,转移为
    $$
    egin{cases}f_{k,0}=sum_{xin son_{k}}f_{x,0}+max_{Ssubseteq son_{k},|S|le K}sum_{xin S}(f_{x,1}+val_{k,x}-f_{x,0})\f_{k,1}=sum_{xin son_{k}}f_{x,0}+max_{Ssubseteq son_{k},|S|<K}sum_{xin S}(f_{x,1}+val_{k,x}-f_{x,0})end{cases}
    $$
    (其中$son_{k}$为$k$儿子的集合,$val_{x,y}$表示边$(x,y)$的边权)

    对于后者,我们可以维护一个数据结构,支持加入一个元素和查询最大的$K$(或$K-1$)个元素之和

    可以使用平衡树/权值线段树实现,单次复杂度为$o(log n)$,总复杂度为$o(nlog n)$

    记$deg_{k}$为节点$k$的度数,将所有边$(x,y)$分为三类:

    1.$deg_{x},deg_{y}le K$,这一类边一定可以选择,直接将$val_{(x,y)}$加入答案并删除

    2.$deg_{x}le K<deg_{y}$,这一类边实际上仅在$y$上有限制,我们可以在求$f_{y,0/1}$时的平衡树中先加入此边权即可

    另外,为了维护,在dp结束后要删除$f_{x,1}+val_{k,x}-f_{x,0}$,如果直接在multiset中删除会导致节点个数

    3.$deg_{x},deg_{y}>K$,这一类边用之前的dp即可

    由此,每一次dp的节点数只有$deg_{k}>K$的节点,而$sum_{K=0}^{n-1}sum_{deg_{k}> K}1=o(n)$,总复杂度即$o(nlog n)$

    (另外注意搜索时,$deg_{k}>K$的点的出边中要删除$deg_{k}le K$的点,来保证复杂度)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 100005
     4 #define ll long long
     5 #define pii pair<int,int>
     6 #define mid (l+r>>1)
     7 struct Edge{
     8     int nex,to,len;
     9 }edge[N<<1];
    10 vector<pii>G[N];
    11 vector<ll>ans,v[N];
    12 int E,V,n,tmp,r[N],id[N],head[N],work[N],vis[N],rt[N],ls[N*100],rs[N*100],sz[N*100];
    13 ll sum,f[N*100],dp[N][2];
    14 bool cmp1(int x,int y){
    15     return r[x]<r[y];
    16 }
    17 bool cmp2(pii x,pii y){
    18     return r[x.first]>r[y.first];
    19 }
    20 void update(int &k,int l,int r,int x,int y){
    21     if (!k)k=++V;
    22     sz[k]+=y,f[k]+=x*y;
    23     if (l==r)return;
    24     if (x<=mid)update(ls[k],l,mid,x,y);
    25     else update(rs[k],mid+1,r,x,y);
    26 }
    27 ll query(int k,int l,int r,int x){
    28     if (l==r)return 1LL*min(x,sz[k])*l;
    29     if (sz[rs[k]]>=x)return query(rs[k],mid+1,r,x);
    30     return f[rs[k]]+query(ls[k],l,mid,x-sz[rs[k]]);
    31 }
    32 void add(int x,int y,int z){
    33     edge[E].nex=head[x];
    34     edge[E].to=y;
    35     edge[E].len=z;
    36     head[x]=E++;
    37 }
    38 void dfs(int k){
    39     vis[k]=1;
    40     dp[k][0]=dp[k][1]=0;
    41     for(int &i=work[k];i!=-1;i=edge[i].nex)
    42         if (r[edge[i].to]>tmp)break;
    43     for(int i=work[k];i!=-1;i=edge[i].nex)
    44         if (!vis[edge[i].to]){
    45             dfs(edge[i].to);
    46             dp[k][0]+=dp[edge[i].to][0];
    47             ll s=dp[edge[i].to][1]+edge[i].len-dp[edge[i].to][0];
    48             if (s>0){
    49                 update(rt[k],1,1e9,s,1);
    50                 v[k].push_back(s);
    51             }
    52         }
    53     dp[k][1]=dp[k][0];
    54     dp[k][0]+=query(rt[k],1,1e9,tmp);
    55     dp[k][1]+=query(rt[k],1,1e9,tmp-1);
    56     for(int i=0;i<v[k].size();i++)update(rt[k],1,1e9,v[k][i],-1);
    57     v[k].clear();
    58 }
    59 vector<ll> minimum_closure_costs(int n,vector<int>u,vector<int>v,vector<int>w){
    60     memset(head,-1,sizeof(head));
    61     for(int i=0;i<=n-2;i++){
    62         u[i]++,v[i]++;
    63         G[u[i]].push_back(make_pair(v[i],w[i]));
    64         G[v[i]].push_back(make_pair(u[i],w[i]));
    65         sum+=w[i];
    66     }
    67     for(int i=1;i<=n;i++){
    68         id[i]=i;
    69         r[i]=G[i].size();
    70     }
    71     sort(id+1,id+n+1,cmp1);
    72     for(int i=1;i<=n;i++){
    73         sort(G[i].begin(),G[i].end(),cmp2);
    74         for(int j=0;j<G[i].size();j++)add(i,G[i][j].first,G[i][j].second);
    75     }
    76     memcpy(work,head,sizeof(work));
    77     ans.push_back(sum);
    78     for(int i=1,j=1;i<n;i++){
    79         while ((j<=n)&&(r[id[j]]<=i)){
    80             for(int k=head[id[j]];k!=-1;k=edge[k].nex){
    81                 if (vis[edge[k].to])sum-=edge[k].len;
    82                 else update(rt[edge[k].to],1,1e9,edge[k].len,1);
    83             }
    84             vis[id[j++]]=1;
    85         }
    86         tmp=i;
    87         ans.push_back(sum);
    88         for(int k=j;k<=n;k++)
    89             if (!vis[id[k]]){
    90                 dfs(id[k]);
    91                 ans[i]-=dp[id[k]][0];
    92             }
    93         for(int k=j;k<=n;k++)vis[id[k]]=0;
    94     }
    95     return ans;
    96 }
    View Code
  • 相关阅读:
    java 集合排序
    java传值和传址
    Dom4j操作xml
    JAXP操作xml
    乐观锁和悲观锁【转】
    java IO【转】
    java 可变参数
    Eclipse调试Java的10个技巧【转】
    编译JDK源代码【转】
    Access restriction: The method typeNameToClass(String) from the type ObjectHandler is not accessible due to restriction on required library
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14970654.html
Copyright © 2011-2022 走看看