zoukankan      html  css  js  c++  java
  • bzoj3672: [Noi2014]购票

    斜率优化+树分治。

    点分治:找出当前子树的重心,分治根到重心这一段,更新根到重心这一段的值,将剩下的点按能到达的高度从低到高排序,更新。分治其他子树。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define LL long long 
    using namespace std;
    const int maxn = 400000 + 10;
    const int maxm = 400000 + 10;
    
    int g[maxn],v[maxn],next[maxn],eid;
    LL w[maxn];
    int n,m,tot,root,t;
    LL f[maxn],d[maxn],p[maxn],q[maxn],lim[maxn];
    int fa[maxn],ms[maxn],size[maxn];
    int seq[maxn],cnt;
    int stack[maxn],sp;
    double k[maxn];
    bool mark[maxn];
    
    void addedge(int a,int b,LL C) {
        v[eid]=b; w[eid]=C; next[eid]=g[a]; g[a]=eid++;    
    }
    
    void dfs(int u) { 
        for(int i=g[u];~i;i=next[i]) {
            d[v[i]]=d[u]+w[i];
            dfs(v[i]);
        }
    }
    
    void get(int u) { 
        ms[u]=0; size[u]=1;
        for(int i=g[u];~i;i=next[i]) if(!mark[i]) {
            get(v[i]);
            size[u]+=size[v[i]];
            ms[u]=max(ms[u],size[v[i]]); 
        }
        ms[u]=max(ms[u],tot-size[u]);
        if(ms[u]<ms[root]) root=u;
    }
    
    double slope(int x,int y) {
        return (double)(f[x]-f[y])/(double)(d[x]-d[y]);    
    }
    
    void update(int x,int y) {
        if(d[x]-d[y]<=lim[x])
        f[x]=min(f[x],f[y]+(d[x]-d[y])*p[x]+q[x]);    
    }
    
    void visit(int u) {
        seq[++cnt]=u;
        for(int i=g[u];~i;i=next[i]) 
            if(!mark[i]) visit(v[i]);
    }
    
    void insert(int x) {
        while(sp>1 && slope(x,stack[sp])>slope(stack[sp],stack[sp-1])) sp--;
        stack[++sp]=x; k[sp]=-slope(x,stack[sp-1]);
    }
    
    bool cmp(int x,int y) {
        return d[x]-lim[x]>d[y]-lim[y];
    }
    
    void solve(int u) {
        if(tot<=1) return;
        root=0; get(u);
        int tmp=root;
        for(int i=g[fa[tmp]];~i;i=next[i]) if(!mark[i]&&v[i]==tmp) {
            mark[i]=1; tot=size[u]-size[v[i]]; solve(u); break;
        }
        for(int i=fa[tmp];i!=fa[u];i=fa[i]) update(tmp,i);
        
        cnt=0;
        for(int i=g[tmp];~i;i=next[i]) if(!mark[i]) visit(v[i]);
        sort(seq+1,seq+cnt+1,cmp);
        
        sp=0;
        for(int i=1,j=tmp;i<=cnt;i++) {
            int y=seq[i];
            for(;j!=fa[u]&&d[j]>=d[y]-lim[y];j=fa[j]) insert(j);
            if(!sp) continue;
            else if(sp==1) update(y,stack[sp]);
            else update(y,stack[min(sp,(int)(upper_bound(k+2,k+sp+1,-p[y])-k-1))]);
        }
        
        for(int i=g[tmp];~i;i=next[i]) if(!mark[i]) {
            mark[i]=1; tot=size[v[i]]; solve(v[i]);
        }
    }
    
    int main() {
        memset(g,-1,sizeof(g));
        scanf("%d%d",&n,&t);
        ms[0]=1000000000;
        for(int i=2,x,y;i<=n;i++) {
            scanf("%d%d%lld%lld%lld",&fa[i],&y,&p[i],&q[i],&lim[i]);
            addedge(fa[i],i,y);
            f[i]=1ll<<62;
        }
        dfs(1); tot=n;
        solve(1);
        for(int i=2;i<=n;i++) printf("%lld
    ",f[i]);
        return 0;
    }
  • 相关阅读:
    【重点】Java大厂面试10个知识点汇总
    TEC-2机微程序设计
    Component 'TABCTL32.OCX'错误的处理方法
    Azure DevOps的使用入门
    Mac + VMware Fusion + Windows 11尝鲜
    Golang接口类型-下篇
    Golang接口类型-上篇
    基于Python实现原生的登录验证码
    一套帮助你理解C语言的测试题(转)
    KMP算法详解
  • 原文地址:https://www.cnblogs.com/invoid/p/5643093.html
Copyright © 2011-2022 走看看