• luogu5021 [NOIp2018]赛道修建 (二分答案+dp(贪心?))


    首先二分一下答案,就变成了找长度>=m的 不相交的路径的个数

    考虑到在一个子树中,只有一个点能出这个子树去和别的点搞

    所以我这个子树里尽量自我满足是不会有坏处的

    而且要在自我满足数最大的条件下,剩下一个尽量大的去把他搞出去

    具体来说,我们设f[x]是x的子树中的满足条件的最大路径数,g[x]是在f[x]最大的情况下能剩下来的x的子树中到x的最大的路径长度

    我们假设y们是x的孩子们,那我们拿着g[y]+edge[x][y],又可以拼出好多路径

    首先如果他已经>=m了,那就直接f[x]++

    然后我把剩下的排个序,开一个l一个r,对着扫,我找能满足它的最小的那个,然后把他俩踢掉

    但踢完以后我还要把r往右搞,因为有可能再把它往左搞的话他就不能满足新的l+1了

    所以需要用一个双向链表来做

    但还有一个问题,我不能在l>=r的时候就直接跳出,考虑1 2 4 5,我第一次做完以后l指在4 r也指在4 所以我要让r再跳一跳,直到他跳出去了在结束

    还是看代码吧...

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 typedef long long ll;
     6 const int maxn=5e4+10;
     7 
     8 inline ll rd(){
     9     ll x=0;char c=getchar();int neg=1;
    10     while(c<'0'||c>'9'){
    11         if(c=='-') neg=-1;
    12         c=getchar();
    13     }
    14     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    15     return x*neg;
    16 }
    17 
    18 int eg[maxn*2][3],egh[maxn],ect;
    19 int N,M,f[maxn],g[maxn],son[maxn],sh;
    20 int nxt[maxn],pre[maxn];
    21 
    22 inline void adeg(int a,int b,int c){
    23     eg[++ect][0]=b,eg[ect][1]=c,eg[ect][2]=egh[a],egh[a]=ect;
    24 }
    25 
    26 inline bool cmp(int a,int b){
    27     return g[a]<g[b];
    28 }
    29 
    30 void dfs(int x,int fa,int k){
    31     f[x]=g[x]=0;
    32     for(int i=egh[x];i;i=eg[i][2]){
    33         int b=eg[i][0];if(b==fa) continue;
    34         dfs(b,x,k);
    35     }sh=0;
    36     for(int i=egh[x];i;i=eg[i][2]){
    37         int b=eg[i][0];if(b==fa) continue;
    38         son[++sh]=b;
    39         g[b]+=eg[i][1];f[x]+=f[b];
    40     }
    41     sort(son+1,son+sh+1,cmp);
    42     int l=1,r=sh;
    43     pre[0]=0;nxt[0]=1,pre[sh+1]=sh;nxt[sh+1]=0;
    44     for(int i=1;i<=sh;i++){
    45         pre[i]=i-1;nxt[i]=i+1;
    46     }
    47     for(;r;r=pre[r]){
    48         if(g[son[r]]<k) break;
    49         f[x]++;
    50         pre[nxt[r]]=pre[r],nxt[pre[r]]=nxt[r];
    51     }
    52     for(;l<=sh;l=nxt[l]){
    53         for(;l<pre[r]&&g[son[l]]+g[son[pre[r]]]>=k;r=pre[r]);
    54         if(l<r&&r<=sh&&g[son[l]]+g[son[r]]>=k){
    55             f[x]++;
    56             pre[nxt[r]]=pre[r],nxt[pre[r]]=nxt[r];
    57             pre[nxt[l]]=pre[l],nxt[pre[l]]=nxt[l];
    58             r=nxt[r];
    59         }
    60         while(nxt[l]<=sh&&r<=nxt[l]) r=nxt[r];
    61     }
    62     if(pre[sh+1]) g[x]=g[son[pre[sh+1]]];
    63 }
    64 inline bool judge(int k){ 
    65     dfs(1,0,k);
    66     return f[1]>=M;
    67 }
    68 
    69 int main(){
    70     // freopen("track.in","r",stdin);
    71     // freopen("track.out","w",stdout);
    72     int i,j,k;
    73     N=rd(),M=rd();
    74     int l=0,r=0,ans=0;
    75     for(i=1;i<N;i++){
    76         int a=rd(),b=rd(),c=rd();
    77         r+=c;
    78         adeg(a,b,c);adeg(b,a,c);
    79     }
    80     while(l<=r){
    81         int m=l+r>>1;
    82         if(judge(m)) l=m+1,ans=m;
    83         else r=m-1;
    84     }
    85     printf("%d
    ",ans);
    86     
    87     return 0;
    88 }
  • 相关阅读:
    vision transformer
    亮剑,gacutil.exe
    MOSS自定义登陆页面
    查看应用程序的进程ID
    基于AD的表单认证 Moss2010
    js 实现拖动
    获取指定数据库表, 以及指定表的数据信息
    二分法
    JZ053表示数值的字符串
    JZ054字符流中第一个不重复的字符
  • 原文地址:https://www.cnblogs.com/Ressed/p/9982090.html
Copyright © 2020-2023  润新知