1. 程式人生 > >賽道修建

賽道修建

在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
看到“最小值最大”首先可以先二分答案ans,問題就變成為、判斷能否選擇m條長度至少是ans的鏈。
考慮以x為根的子樹,最優解中有一些鏈完全在子樹內部,還可能有一條鏈經過x並向子樹外擴充套件。可以證明一定存在一個最優解使得完全在子樹內部的鏈儘可能多,否則可以調整子樹內部的方案,不會使答案變差。而如果有兩種方案使得子樹內部的鏈一樣多,我們肯定儘量使剩下可以往上擴充套件的鏈儘可能長(如果沒有就是0)
我們用opt(t)表示子樹內部的鏈最多有多少條,len(x)表示當子樹內部鏈的個數最多時,空餘的以x結尾的鏈最長是多少。

我一開始沒有用二分,導致整個程式超時,只有30分TAT ,TODO改進這個匹配,好像有點問題,有好心人看到麻煩解答一下(Thanks♪(・ω・)ノ

#include<bits/stdc++.h>
using namespace std;
inline int read()
{
 int a=0;
 char l=0,c=getchar();
 while(c<'0'||c>'9')
  l=c,c=getchar();
 while(c>='0'&&c<='9')
  a=a*10+c-'0',c=getchar();
 return l=='-'?-a:a;
}
inline int max(int a,int b){return a>b?a:b;}
const int maxn=5e4;
int
n,m; struct edge { int v,w; edge *next; }edge_mem[2*maxn+100]; edge *edge_memp; struct node { edge *head; }nodes[maxn+100]; inline void make_edge(int u,int v,int w) { edge *p=edge_memp++; p->v=v; p->w=w; p->next=nodes[u].head; nodes[u].head=p; } int c[maxn+100]; int d[maxn+100]; int l; //int a[maxn+100];
//int a_cnt; inline bool cmp(int a,int b){return a>b;} multiset<int>st; void func(int u,int f) { c[u]=0; for(edge*p=nodes[u].head;p;p=p->next) { if(p->v==f) continue; func(p->v,u); c[u]+=c[p->v]; } //if(l==8)printf("@%d\n",u); //a_cnt=0; st.clear(); for(edge*p=nodes[u].head;p;p=p->next) { if(p->v==f) continue; if(d[p->v]+p->w>=l) { ++c[u]; } else { st.insert(d[p->v]+p->w); //a[++a_cnt]=d[p->v]+p->w; } } //匹配 d[u]=0; while(!st.empty()) { multiset<int>::iterator i=st.begin(); int i_v=*i; st.erase(i); multiset<int>::iterator j=st.lower_bound(l-i_v); if(j!=st.end()) { c[u]++; st.erase(j); } else { d[u]=max(d[u],i_v); } } //匹配 //TODO改進這個匹配,好像有點問題 //std::sort(a+1,a+a_cnt+1,cmp); //for(inti=1,j=a_cnt;i<=j;++i) //{ // while(i<=j) // if(a[i]+a[j]>=l&&i<j) // break; // else // d[u]=max(d[u],a[j]),--j; // if(i<j) // { // printf("!"); // ++c[u]; // --j; // } //} // if(l==8) // { // printf("%d\n",c[u]); // } } inline bool valid(int t) { l=t; memset(c,0,sizeof c); memset(d,0,sizeof d); func(1,0); return c[1]>=m; } int main() { n=read(),m=read(); memset(nodes,0,sizeof nodes); edge_memp=edge_mem; for(int i=1;i<n;++i) { int u=read(),v=read(),w=read(); make_edge(u,v,w); make_edge(v,u,w); } int l=0,r=5e8; while(l<r) { int t=((l+r)>>1)+1; if(valid(t)) { l=t; } else { r=t-1; } } printf("%d",l); return 0; }