題面c++
英文題面git
題意:有一棵\(n\)個點的樹,每條邊的邊權是一個一次函數\(a_i\times t +b_i\)。求對於全部的\(t\in [0,m-1]\)的樹的直徑。算法
\(n \leq 10^5,m\leq 10^6,a_i\leq 10^5,b_i \leq 10^9\)。函數
題解:首先,最暴力的作法就是枚舉\(t\),每次算出邊權後後都dp一次,這樣是\(O(nm)\)的。發現咱們很難優化這個算法,因此考慮採用逆向思惟。優化
因爲邊權非負,直徑的兩端點必定是葉子結點。因此咱們能夠枚舉全部葉子結點兩兩的距離,這個距離也能夠表示爲一條線段,那麼咱們獲得了\(O(n^2)\)條線段。能夠想象,最後的答案必定是一個凸殼,咱們用李超線段樹維護,或者直接維護就好了。ui
這樣作仍是不夠優秀,考慮用樹分治來優化加入線段的過程。spa
對於樹上點對距離這種東西,不難想到用點分治。可是因爲分治中心有不少個子樹,若是要合併,就得兩兩枚舉,這樣複雜度是\(O(nlog^2n)\)。這時咱們想到邊分治只須要考慮兩個子樹,因此用邊分治作就好了。因爲合併兩個凸包的時間複雜度是\(O(siz1+siz2)\)的,因此邊分治的時間複雜度就是\(O(nlogn)\)的。code
最後將全部合併的凸包搞成一個大凸包,掃一遍便可。get
時間複雜度:\(O(nlogn)\)。it
代碼:
#include<bits/stdc++.h> using namespace std; #define re register int #define F(x,y,z) for(re x=y;x<=z;x++) #define FOR(x,y,z) for(re x=y;x>=z;x--) typedef long long ll; typedef __int128 LL; #define I inline void #define IN inline int #define C(x,y) memset(x,y,sizeof(x)) #define STS system("pause") template<class D>I read(D &res){ res=0;register D g=1;register char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')g=-1; ch=getchar(); } while(isdigit(ch)){ res=(res<<3)+(res<<1)+(ch^48); ch=getchar(); } res*=g; } template<class D>I write(D X) { if(X<0) {X=~(X-1); putchar('-');} if(X>9) write(X/10); putchar(X%10+'0'); } const int INF=1e9+7; typedef pair<ll,ll>pii; struct P{ ll x,y; P(ll _x=0,ll _y=0){x=_x;y=_y;} friend P operator + (P a,P b){return P(a.x+b.x,a.y+b.y);} friend P operator - (P a,P b){return P(a.x-b.x,a.y-b.y);} friend LL operator ^ (P a,P b){return (LL)a.x*b.y-(LL)a.y*b.x;} friend bool operator < (P a,P b){return a.x==b.x?a.y<b.y:a.x<b.x;} inline ll get(ll w){return x*w+y;} }p[4040000],st[4040000]; struct Edge{ int x,y;ll a,b; Edge(int _x=0,int _y=0,ll _a=0,ll _b=0){x=_x;y=_y;a=_a;b=_b;} }; vector<Edge>vec; struct E{ int to,nt;ll a,b;bool v; }e[808000]; #define T e[k].to int n,m,M,maxi,cnt,head[404000],num[101000],tot,X,Y,A,B,siz[404000]; P t1[404000],t2[404000]; int cnt1,cnt2; I add(int x,int y,ll nowa,ll nowb){ //cout<<x<<" "<<y<<" "<<nowa<<" "<<nowb<<endl; e[++tot].to=y;e[tot].nt=head[x];head[x]=tot;e[tot].a=nowa;e[tot].b=nowb; } I insert(int x,int y,ll nowa,ll nowb){ ++cnt; vec.emplace_back(Edge(num[x],cnt,0,0)); vec.emplace_back(Edge(cnt,y,nowa,nowb)); num[x]=cnt; } I D_1(int x,int fa){ for(re k=head[x];k!=-1;k=e[k].nt){ if(T==fa)continue; insert(x,T,e[k].a,e[k].b);D_1(T,x); } } I D_2(int x,int fa){ siz[x]=1; for(re k=head[x];k!=-1;k=e[k].nt){ if(T==fa||e[k].v)continue; D_2(T,x);siz[x]+=siz[T]; } } I findroot(int x,int fa,int N){ for(re k=head[x];k!=-1;k=e[k].nt){ if(T==fa||e[k].v)continue; findroot(T,x,N); re now=max(siz[T],N-siz[T]); if(maxi>now)maxi=now,M=k; } } I D_3(int x,int fa,ll suma,ll sumb){ //cout<<"!"<<x<<" "<<fa<<" "<<suma<<" "<<sumb<<endl; if(suma||sumb)t1[++cnt1]=P(suma,sumb); for(re k=head[x];k!=-1;k=e[k].nt){ if(T==fa||e[k].v)continue; D_3(T,x,suma+e[k].a,sumb+e[k].b); } } I D_4(int x,int fa,ll suma,ll sumb){ // cout<<"!"<<x<<" "<<fa<<" "<<suma<<" "<<sumb<<endl; if(suma||sumb)t2[++cnt2]=P(suma,sumb); for(re k=head[x];k!=-1;k=e[k].nt){ if(T==fa||e[k].v)continue; D_4(T,x,suma+e[k].a,sumb+e[k].b); } } I build(P *t,int &sum){ sort(t+1,t+1+sum);re top=0; F(i,1,sum){ while(top>1&&(P(st[top]-st[top-1])^P(t[i]-st[top-1]))>=(LL)0)--top; st[++top]=t[i]; } sum=top; //cout<<"Convex:"<<endl; F(i,1,sum)t[i]=st[i];//,cout<<"("<<t[i].x<<" "<<t[i].y<<")"<<endl; } I merge(){ re j=min(1,cnt1),k=min(1,cnt2);re las=cnt+1; p[++cnt]=t1[j]+t2[k]; while(j<cnt1&&k<cnt2){ if((P(t2[k+1]-t2[k])^P(t1[j+1]-t1[j]))>=(LL)0)p[++cnt]=P(t1[++j]+t2[k]); else p[++cnt]=P(t1[j]+t2[++k]); } while(j<cnt1)p[++cnt]=P(t1[++j]+t2[cnt2]); while(k<cnt2)p[++cnt]=P(t1[cnt1]+t2[++k]); //cout<<"new:"<<endl; //F(i,las,cnt)cout<<"("<<p[i].x<<" "<<p[i].y<<")"<<endl; } I solve(int x){ //cout<<x<<" "; D_2(x,0);if(siz[x]==1)return; maxi=INF;findroot(x,0,siz[x]); re rta=e[M^1].to,rtb=e[M].to; //cout<<rta<<" "<<rtb<<":"<<endl; e[M^1].v=e[M].v=1;cnt1=cnt2=0; D_3(rta,0,e[M].a,e[M].b);build(t1,cnt1); D_4(rtb,0,0,0);build(t2,cnt2); merge(); solve(rta);solve(rtb); } int main(){ //freopen("rain.out","w",stdout); read(n);read(m);C(head,-1);tot=-1;cnt=n; F(i,1,n)num[i]=i; F(i,1,n-1){ read(X);read(Y);read(A);read(B); e[++tot]=(E){Y,head[X],A,B},head[X]=tot; e[++tot]=(E){X,head[Y],A,B},head[Y]=tot; } D_1(1,0);C(head,-1);tot=-1;cnt=0; for(auto p:vec)add(p.x,p.y,p.a,p.b),add(p.y,p.x,p.a,p.b); solve(1);build(p,cnt); n=1; // F(i,1,cnt)cout<<p[i].x<<" "<<p[i].y<<endl; F(i,0,m-1){ while(n<cnt&&p[n+1].get(i)>p[n].get(i))n++; write(p[n].get(i));putchar(10); } return 0; }