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\n",ans);
86     
87     return 0;
88 }

猜你喜欢

转载自www.cnblogs.com/Ressed/p/9982090.html