【点分治】【数据结构】Codeforces1019E Raining season

题意:

给出一棵树,每条边的距离都是一个一次函数,给出斜率k和截距m。(y=k*x+m)
现在求当x=0,1,2,……,t-1时,整个图中最远点的距离。


分析:

这题一股浓郁的OI气息啊。。。(思路简单实现复杂的数据结构题)

首先,如果不考虑那个神奇的边权,那么就是一个简单的点分治水题。。。

现在考虑加上这个边权,很容易发现,最终答案一定是一个下凸壳。

所以可以用一个multiset维护这个凸壳中的所有边,以及边之间的交点。由于每层有n个叶子节点,然后有logn层,所以总共的线段数不超过nlogn。。。

具体实现看代码吧,注释应该够详细了

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 100010
#define INF 0x3FFFFFFF
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
bool Q;
struct Line{
    mutable ll k,m,p;//slope,intercept,intersection
    Line () {}
    Line (ll k1,ll m1,ll p1):k(k1),m(m1),p(p1) {}
    bool operator < (const Line & a) const {
        if(Q==1)
            return p<a.p;
        else
            return k<a.k;
    }
};
typedef multiset<Line>::iterator mult ;
struct LC : multiset<Line>{//maintain the lines,sperated by the intersection
    ll inf=1ll*INF*INF;
    ll flr(ll a,ll b){
        if((a^b)<0)
            return a/b-((a%b)!=0);
        else
            return a/b;
    }
    bool compare(iterator x,iterator y){//check: whether the x cover y or not (Slope of x is not bigger than y)
        if(y==end()){//y is the end of the set
            x->p=inf;
            return 0;
        }
        if(x->k==y->k){//compare the intercept
            if(x->m>y->m)
                x->p=inf;
            else
                x->p=-inf;  
        }
        else
            x->p=flr(y->m - x->m,x->k - y->k);
        return x->p >= y->p;
    }
    void add(ll k,ll m){//add the line with slope = k ,intercept = m in the set
        multiset<Line>::iterator z=insert(Line(k,m,0));
        multiset<Line>::iterator y=z++;
        multiset<Line>::iterator x=y;
        while(compare(y,z))//compare the latter
            z=erase(z);
        if(x!=begin()&&compare(--x,y)){//get the intersection
            y=erase(y);
            compare(x,y);   
        }
        y=x;
        while(y!=begin()&&(--x)->p>=y->p){//compare the former
            y=erase(y);
            compare(x,y);
            y=x;
        }
    }
    ll que(ll x){
        Q=1;
        mult l=lower_bound(Line(0,0,x));
        Q=0;
        return l->k*x+l->m;
    }
}ans;
vector<int> a[MAXN];
vector<ll> K[MAXN],M[MAXN];
int siz[MAXN];
bool vis[MAXN];
int cent=-1,mins;
int dfs(int x,int fa){
    siz[x]=1;
    for(int i=0;i<a[x].size();i++){
        int u=a[x][i];
        if(u==fa||vis[u])
            continue;
        siz[x]+=dfs(u,x);
    }
    return siz[x];
}

void find_c(int x,int fa,int sum){
    int mxsiz=sum-siz[x];
    for(int i=0;i<a[x].size();i++){
        int u=a[x][i];
        if(u==fa||vis[u])
            continue;
        mxsiz=max(mxsiz,siz[u]);
        find_c(u,x,sum);
    }
    if(cent==-1||mins>mxsiz){
        mins=mxsiz;
        cent=x; 
    }
}

int get_c(int x){
    if(vis[x]==1)
        return -1;
    cent=-1;
    mins=0; 
    int sum=dfs(x,-1);
    find_c(x,-1,sum);
    return cent;
}
vector<pll> ans1;
void update_ans(const LC &a,const LC &b){//merge and use them to update ans
    vector<pll> linea,lineb;

    for(mult it=a.begin();it!=a.end();it++){
        if(linea.size()>0&&linea[linea.size()-1].first==it->k){
            linea[linea.size()-1].second=max(linea[linea.size()-1].second,it->m);
            continue;
        }
        linea.push_back(make_pair(it->k,it->m));
    }

    for(mult it=b.begin();it!=b.end();it++){
        if(lineb.size()>0&&lineb[lineb.size()-1].first==it->k){
            lineb[lineb.size()-1].second=max(lineb[lineb.size()-1].second,it->m);
            continue;
        }
        lineb.push_back(make_pair(it->k,it->m));
    }


    int l=0,r=0;
    while(l<linea.size()&&r<lineb.size()){
        ans1.push_back(make_pair(linea[l].first+lineb[r].first,linea[l].second+lineb[r].second));
        if(l+1==linea.size())
            r++;
        else if(r+1==lineb.size())
            l++;
        else{
            double p1=-(double)(linea[l+1].second-linea[l].second)/(double)(linea[l+1].first-linea[l].first);
            double p2=-(double)(lineb[r+1].second-lineb[r].second)/(double)(lineb[r+1].first-lineb[r].first);
            if(p1<p2)
                l++;
            else
                r++;
        }
    }
}

LC merge_trees(int l,int r,vector<LC> & s){//merge the route from the different trees
    if(l==r){
        LC l0;
        l0.add(0,0);
        update_ans(l0,s[l]);
        return s[l];
    }
    else{
        int mid=(l+r)>>1;
        LC l1=merge_trees(l,mid,s);
        LC l2=merge_trees(mid+1,r,s);   
        update_ans(l1,l2);
        for(mult it=l1.begin();it!=l1.end();it++)
            l2.add(it->k,it->m);
        return l2;
    }
}

LC li;
void get_l(int x,int fa,ll prk,ll prm){//dfs in the tree
    bool flag=0;
    for(int i=0;i<a[x].size();i++){
        int u=a[x][i];
        if(u==fa||vis[u])
            continue;
        get_l(u,x,prk+K[x][i],prm+M[x][i]);
        flag=1;
    }
    if(!flag){
        li.add(prk,prm);//only the leaf can be the best
    }
}

void solve(int x){//solve the subtree with vertex x
    int centroid=get_c(x);
    if(centroid==-1)
        return ;
    vector<LC> s;
    for(int i=0;i<a[centroid].size();i++){
        int u=a[centroid][i];
        if(vis[u])
            continue;
        li.add(0,0);
        get_l(u,centroid,K[centroid][i],M[centroid][i]);    
        s.push_back(li);
        li.clear();
    }
    if(s.size()>0)
        merge_trees(0,s.size()-1,s);
    vis[centroid]=1;
    for(int i=0;i<a[centroid].size();i++){
        int u=a[centroid][i];
        if(!vis[u]) 
            solve(u);
    }
}
int n,t,u,v,k1,m1;
int main(){
    SF("%d%d",&n,&t);   
    for(int i=1;i<n;i++){
        SF("%d%d%d%d",&u,&v,&k1,&m1);   
        a[u].push_back(v);
        a[v].push_back(u);
        K[u].push_back(k1);
        K[v].push_back(k1);
        M[u].push_back(m1);
        M[v].push_back(m1);
    }
    solve(1);
    ans.add(0,0);
    for(int i=0;i<ans1.size();i++)
        ans.add(ans1[i].first,ans1[i].second);
    for(int i=0;i<t;i++)
        PF("%I64d ",ans.que(i));
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/81625600
今日推荐