• BZOJ3672 NOI2014 购票


    传送门

    题目大意,给定一棵有根树($1$号点是根),每个点有$5$个参数$fa,len,d,cst,unt$

    $fa$表示点$x$的父节点编号,$d$表示$x$到父节点的距离。

    在$x$可以花费$dis(x,y) imes unt_x+cst_x$的价格到达$x$的祖先$y$,其中$dis(x,y)$为$x$到$y$的距离,且必须满足$dis(x,y)leq len_x$,求每个点到根的最小代价。

     

    先考虑如果树是一条链怎么做,显然只是一个可以斜率优化的递推式。

    $F_i$表示从$i$出发的最小代价,$dep_i$表示$i$到根的距离

    $F_i=min{F_j+cst_i(dep_i-dep_j)+unt_i}(dep_i-dep_jleq len_i)$

    $F_i-cst_i imes dep_i-unt_i+cst_i imes dep_j=F_j$

    令$X_k=dep_k,Y_k=F_k$,那么问题就出转化为了求斜率为$cst_i$的过$(X_j,Y_j)$之一的直线使得与$y$轴截距最小,由于有一个$len$的范围,所以没有办法直接扫一遍维护下凸壳,我们只能采用$CDQ$分治,考虑前半部分的点对后半部分的贡献,将后半部分的点按照$dep_x-len_x$降序排序,前半部分的点按照$X_k$降序,每次动态由$X_k$从大到小的顺序插入满足$dep_kgeq dep_x-len_x$的$X_k,Y_k$维护下凸壳,再在凸壳上进行二分即可。

    思考如何把$CDQ$分治转到树上,其实只需要每次找到树分治区域的重心,优先处理重心靠近根一侧的部分,在暴力更新一遍重心,然后将重心的儿子的子树的点拿出来按照$dep_x-len_x$降序排序,再把重心在分治区内的所有祖先依次拿出来维护凸壳用来更新,就完成了在树上的$CDQ$分治。

    最终复杂度为$O(Nlog^2N)$。

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define M 400020
    #define INF 4000000000000000ll
    using namespace std;
    const int BufferSize=1<<19;
    char buffer[BufferSize],*head,*tail;
    char Getchar(){
        if(head==tail){
            int l=fread(buffer,1,BufferSize,stdin);
            tail=(head=buffer)+l;
        } return *head++;
    }
    LL read(){
    	LL nm=0,fh=1; char cw=Getchar();
    	for(;!isdigit(cw);cw=Getchar()) if(cw=='-') fh=-fh;
    	for(;isdigit(cw);cw=Getchar()) nm=nm*10+(cw-'0');
    	return nm*fh;
    }
    void write(LL x){if(x>9) write(x/10);putchar(x%10+'0');}
    int n,m,sz[M],fs[M],to[M],nt[M],fa[M],tmp,root,mxs[M],top,S[M],sum,maxn,P[M];
    LL F[M],dep[M],C[M],D[M],len[M],tot;
    bool vis[M]; double Y(int i){return F[i]*1.0;} double X(int i){return dep[i]*1.0;}
    bool conv(int t1,int t2,int t3){return (Y(t3)-Y(t2))*(X(t2)-X(t1))>(Y(t2)-Y(t1))*(X(t3)-X(t2));}
    void link(int x,int y){nt[tmp]=fs[x],fs[x]=tmp,to[tmp++]=y;}
    void init(int x){dep[x]+=dep[fa[x]];for(int i=fs[x];i!=-1;i=nt[i]) init(to[i]);}
    bool cmp(int x,int y){return dep[x]-len[x]>dep[y]-len[y];}
    LL getans(int i,int j){return F[j]+(dep[i]-dep[j])*C[i]+D[i];}
    void fdrt(int x){
    	sz[x]=1,mxs[x]=0;
    	for(int i=fs[x];i!=-1;i=nt[i])
    		if(!vis[to[i]]) fdrt(to[i]),mxs[x]=max(mxs[x],sz[to[i]]),sz[x]+=sz[to[i]];
    	mxs[x]=max(mxs[x],sum-sz[x]); if(mxs[x]<maxn) maxn=mxs[x],root=x;
    }
    void ins(int x){while(tot>1&&!conv(x,P[tot],P[tot-1])) tot--; P[++tot]=x;}
    void upd(int x){
    	if(!tot) return;
    	int md,mx=tot,mi=2,res=0; F[x]=min(F[x],getans(x,P[1]));
    	while(mi<=mx){
    		md=((mx+mi)>>1);
    		if(getans(x,P[md])>getans(x,P[md-1])) mx=md-1;
    		else mi=md+1,res=P[md];
    	} if(res) F[x]=min(F[x],getans(x,res));
    }
    void dp(int x){S[++top]=x;for(int i=fs[x];i!=-1;i=nt[i]) if(!vis[to[i]]) dp(to[i]);}
    void solve(int anc,int x){
    	vis[x]=true,tot=top=0;
    	if(anc!=x) sum=sz[anc]-sz[x],maxn=M,fdrt(anc),solve(anc,root),tot=top=0;
    	for(int i=fs[x];i!=-1;i=nt[i]) if(!vis[to[i]]) dp(to[i]);
    	for(int y=x;y!=anc;y=fa[y]){
    		if(dep[x]-dep[fa[y]]>len[x]) break;
    		F[x]=min(F[x],getans(x,fa[y]));
    	}
    	sort(S+1,S+top+1,cmp),tot=0;
    	for(int i=1,now=x;i<=top;upd(S[i]),i++){
    		while(now!=fa[anc]&&dep[now]>=dep[S[i]]-len[S[i]]) ins(now),now=fa[now];
    	} tot=top=0;
    	for(int i=fs[x];i!=-1;i=nt[i]){
    		if(vis[to[i]]) continue; tot=top=0,maxn=M;
    		sum=sz[to[i]],fdrt(to[i]),solve(to[i],root),tot=top=0;
    	}
    }
    int main(){
    	n=read(),read(),sum=n,memset(fs,-1,sizeof(fs));
    	memset(F,0x3f,sizeof(F)),F[1]=0;
    	for(int i=2;i<=n;i++){
    		fa[i]=read(),dep[i]=read(),link(fa[i],i);
    		C[i]=read(),D[i]=read(),len[i]=read();
    	} init(1);
    	maxn=M,fdrt(1),solve(1,root);
    	for(int i=2;i<=n;i++) write(F[i]),putchar('
    ');
    	return 0;
    }
    

      

  • 相关阅读:
    selenium2基本控件介绍及其代码
    selenium2元素定位Xpath和cssSelector
    Selenium2启动浏览器且加载插件
    bash之条件测试if/else
    bash脚本编写基础
    Android后台的linux一直保持唤醒状态,不进入睡眠
    Linux任务计划、周期性任务执行
    C#进阶系列——WebApi 跨域问题解决方案:CORS(转载)
    linq group by
    echart 分组属性
  • 原文地址:https://www.cnblogs.com/OYJason/p/9746953.html
Copyright © 2020-2023  润新知