码迷,mamicode.com
首页 > 其他好文 > 详细

CF1019E Raining season

时间:2020-07-21 01:15:15      阅读:57      评论:0      收藏:0      [点我收藏+]

标签:type   题意   ace   ret   cto   一个   pause   优秀   etc   

题面

英文题面

题意:有一棵\(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;
}

CF1019E Raining season

标签:type   题意   ace   ret   cto   一个   pause   优秀   etc   

原文地址:https://www.cnblogs.com/Purple-wzy/p/13347756.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!