CF1019E Raining season
题意:有一棵\(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)\)条线段。可以想象,最后的答案一定是一个凸壳,我们用李超线段树维护,或者直接维护就行了。
这样做还是不够优秀,考虑用树分治来优化加入线段的过程。
对于树上点对距离这种东西,不难想到用点分治。但是由于分治中心有很多个子树,如果要合并,就得两两枚举,这样复杂度是\(O(nlog^2n)\)。这时我们想到边分治只需要考虑两个子树,所以用边分治做就行了。由于合并两个凸包的时间复杂度是\(O(siz1+siz2)\)的,所以边分治的时间复杂度就是\(O(nlogn)\)的。
最后将所有合并的凸包搞成一个大凸包,扫一遍即可。
时间复杂度:\(O(nlogn)\)。
代码:
#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;
}