1. 程式人生 > >luogu5021 [NOIp2018]賽道修建 (二分答案+dp(貪心?))

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 }