BZOJ3672: [Noi2014]购票 树分治 斜率优化

来源:互联网 发布:9788 微信 网络不稳定 编辑:程序博客网 时间:2024/04/30 03:11

http://www.lydsy.com/JudgeOnline/problem.php?id=3672
树上的CDQ分治。
和常规CDQ思路相同,一个点的可行决策点是从这个点往上连续一段,那么在分治过程中先递归重心往上的一块(包括重心这个点),再将其他点按可行深度排序,然后维护上面那些点的凸包来更新底下点的答案,最后分别递归底下的块即可。

#include<cstdio>#include<cstring>#include<cmath>#include<vector>#include<functional>#include<algorithm>#define gm 200001using namespace std;typedef long long ll;int n,p[gm],fa[gm],t;ll q[gm],l[gm],dep[gm];bool ban[gm];struct e{    int t;    e *n;    ll c;    e(int t,e *n,const ll& c):t(t),n(n),c(c){}}*f[gm];void init(int x){for(e *i=f[x];i;i=i->n){dep[i->t]=dep[x]+i->c,init(i->t);}}struct pnt{    ll x,y;    pnt(const ll &x,const ll &y):x(x),y(y){}    ll b(int k){return y-k*x;}};double slope(const pnt &a,const pnt &b){return (double)(a.y-b.y)/(a.x-b.x);}struct hull{    vector<pnt> p;    vector<double> d;    int sz;    hull():p(),d(),sz(){}    ~hull()=default;    void push_back(const pnt &a)    {        if(!sz)        {            p.push_back(a); d.push_back(1e100);            sz=1;        }        else        {            while(sz>1&&slope(p[sz-1],a)>d[sz-1])            {                --sz; p.pop_back(); d.pop_back();            }            p.push_back(a); d.push_back(slope(p[sz-1],a));            ++sz;        }    }    ll find(const ll &k)    {        int pos=upper_bound(d.begin(),d.end(),(double)k,greater<double>())-d.begin()-1;        return p[pos].b(k);    }    bool empty() {return !sz;}};ll dp[gm];int sz[gm];int lim,g;void dfs(int x){    bool is=1;    sz[x]=1;    for(e *i=f[x];i;i=i->n)    {        if(ban[i->t]) continue;        dfs(i->t);        if(sz[i->t]>lim>>1) is=0;        sz[x]+=sz[i->t];    }    if(lim-sz[x]>lim>>1) is=0;    if(is) g=x;}int r[gm],cnt;void push(int x){    r[++cnt]=x;    for(e *i=f[x];i;i=i->n)    {        if(ban[i->t]) continue;        push(i->t);    }}struct cmp{bool operator() (int a,int b){return dep[a]-l[a]>dep[b]-l[b];}};void solve(int rt,int tot){    lim=tot; dfs(rt); int x=g;    vector<int> lst;    for(e *i=f[x];i;i=i->n)    {        if(ban[i->t]) continue;        ban[i->t]=1; lst.push_back(i->t); tot-=sz[i->t];    }    if(rt!=x) solve(rt,tot);    ban[x]=1;cnt=0;    for(vector<int>::iterator it=lst.begin();it!=lst.end();++it){ban[*it]=0; push(*it);}    sort(r+1,r+cnt+1,cmp());    hull h;    for(int i=1;i<=cnt;++i)    {        int y=r[i];        while(x!=fa[rt]&&dep[x]>=dep[y]-l[y]) h.push_back(pnt(dep[x],dp[x])),x=fa[x];        if(!h.empty())        {            ll kre=h.find(p[y]);            dp[y]=min(dp[y],kre+p[y]*dep[y]+q[y]);        }    }    for(vector<int>::iterator it=lst.begin();it!=lst.end();++it){solve(*it,sz[*it]);}}int main(){    scanf("%d%d",&n,&t);    memset(dp+1,0x7f,n<<3); dp[1]=0;    for(int i=2;i<=n;++i)    {        ll len;        scanf("%d%lld%d%lld%lld",fa+i,&len,p+i,q+i,l+i);        f[fa[i]]=new e(i,f[fa[i]],len);    }    init(1);    solve(1,n);    for(int i=2;i<=n;++i) printf("%lld\n",dp[i]);    return 0;}
原创粉丝点击