zoukankan      html  css  js  c++  java
  • 题解[CF932F Escape Through Leaf]

    原题链接

    题意:给定一棵树,每个点有连个值 (a,b)
    每次可以从一个点 (x) 到其子树内一点 (y) 的代价为 (a_x imes b_y)
    求每个到其子树内任一叶子结点的最小代价。
    (n,|a_i|,|b_i|leq 10^5)

    (f_x)(x) 到其子树内任一叶子节点的最小代价,则有 (f_x=mathop{mathrm{Min}}limits_{yin subtree(x)}f_y+a_xb_y)

    这是很明显的斜率优化,每个点的信息可视为 ((b_y,f_y)) ,维护一个下凸壳,然后用斜率为 (-a_x) 的直线截得的截距最小值。这可以用李超树合并或凸包启发式合并无脑实现。

    但事实上分治也可以在 (O(nlog n)) 的时间胜任。

    将子树限制转化到 (dfs) 序上,则 (dfn_x+1leq dfn_yleq dfn_x+sz_x-1) 内的 ((b_y,f_y)) 能贡献给 (x) 所需的点。

    由于区间限制,且查询信息最小值不满足可加性,很自然想到线段树分治。

    (dfs) 序为下标建出线段树。将线段树上在 ([dfn_x+1,dfn_x+sz_x-1]) 的区间内的点打上对 (x) 的标记,表示这部分的点可以更新 (f_x) 。这些标记将是 (O(nlog n)) 个。

    由于能更新 (f_x) 点的 (dfs) 序在 (x) 之后,需要以 ( ext{右左中}) 的顺序遍历线段树。

    类似于 ( ext{cdq}) 分治,处理完右边与左边后将两边 ((b_y,f_y)) 的点集按横坐标归并排序,再维护出些点集的下凸壳,然后找出线段树上这个点能更新的点 (x) 的斜率,在凸壳上查询。

    为了让查询的斜率递增,可以在之前先按斜率排序再在线段树上打标记。

    这能保证查询到某一点 (x)(f_x) 能被所有能更新它的点更新。

    归并排序,维护下凸壳,查询的总时间复杂度都是 (O(nlog n)) 的。

    这可以说是线段树分治也可以说是 ( ext{cdq}) 分治,二者并没有严格的界限。

    本题卡精度,最好把 ( ext{long long}) 换成 ( ext{double})

    代码:

    #include<bits/stdc++.h>
    #define ll double
    using namespace std;
    const int N=2e5+10,M=5e6+10;
    const ll inf=1e18;char ch;
    int n,m,x,y,l_,r_,tt;bool rf;
    inline void read(int &x){
    	x=0;ch=getchar();while(ch<47)ch=getchar();
    	while(ch>47)x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    }
    inline void read_(int &x){
    	rf=x=0;ch=getchar();while((ch<47)&&(ch^'-'))ch=getchar();
    	if(ch=='-')rf=1,ch=getchar();
    	while(ch>47)x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	if(rf)x=-x;
    }
    int nextn[N],to[N],h[N],edg;
    inline void add(int x,int y){to[++edg]=y,nextn[edg]=h[x],h[x]=edg;}
    int nextnq[M],toq[M],hq[N<<2],edgq;
    inline void addq(int x,int y){toq[++edgq]=y,nextnq[edgq]=hq[x],hq[x]=edgq;}
    int dfn[N],sz[N],rev[N],kk[N];ll f[N];
    struct node{int i,a,b;bool operator <(const node &x)const{return a<x.a;}}s[N];
    struct point{
    	ll x,y;point()=default;point(ll _x,ll _y):x(_x),y(_y){}
    	bool operator <=(const point &a)const{return y*a.x<=x*a.y;}
    	point operator -(const point &a)const{return point(x-a.x,y-a.y);}
    }p[N],tmp;
    struct stp{//segmenttree_partition
    	ll x,y;stp()=default;stp(ll _x,ll _y):x(_x),y(_y){}
    	bool operator <(const stp &a)const{return x!=a.x?x<a.x:y>a.y;}
    }q[N],q0[N];
    void init(int x,int anc){
    	int i,y;sz[x]=1;rev[dfn[x]=++tt]=x;
    	for(i=h[x];y=to[i];i=nextn[i])if(y^anc)init(y,x),sz[x]+=sz[y];
    }
    #define ls k<<1
    #define rs k<<1|1
    void add(int k,int l,int r,int x,int y,int i){
    	if(x<=l&&r<=y)addq(k,i);
    	else {
    		int mid=(l+r)>>1;
    		if(x<=mid)add(ls,l,mid,x,y,i);
    		if(mid<y)add(rs,mid+1,r,x,y,i);
    	}
    }//打标记,这里用加边实现
    void solve(int k,int l,int r){
    	int i;
    	if(l^r){
    		int mid=(l+r)>>1;
    		solve(rs,mid+1,r);
    		solve(ls,l,mid);
    		merge(q+l,q+mid+1,q+mid+1,q+r+1,q0+l);
    		for(i=l;i<=r;++i)q[i]=q0[i];
    	}
    	else q[l].y=f[rev[l]];//区间为dfs序,对应树上点rev[l]
    	r_=0;
    	for(i=l;i<=r;++i){
    		tmp=point(q[i].x,q[i].y);
    		while(r_>1&&(tmp-p[r_])<=(p[r_]-p[r_-1]))--r_;
    		p[++r_]=tmp;
    	}//维护区间点集的下凸壳
    	l_=1;
    	for(i=hq[k];y=toq[i];i=nextnq[i]){
    		tmp=point(1,kk[y]);
    		while(l_<r_&&(p[l_+1]-p[l_])<=tmp)++l_;
    		f[y]=min(f[y],p[l_].y-p[l_].x*tmp.y);
    	}//更新f
    }
    main(){
    	read(n);register int i;
    	for(i=1;i<=n;++i)read_(s[i].a),kk[i]=-s[i].a;
    	for(i=1;i<=n;++i)read_(s[i].b),s[i].i=i,f[i]=inf;
    	for(i=1;i^n;++i)read(x),read(y),add(x,y),add(y,x);
    	init(1,0);
    	for(i=1;x=rev[i],i<=n;++i)q[i]=stp(s[x].b,0);
    	sort(s+1,s+n+1);//排序保证线段树上查询时斜率递增
    	for(i=1;x=s[i].i,i<=n;++i){
    		if(sz[x]^1)add(1,1,n,dfn[x]+1,dfn[x]+sz[x]-1,x);
    		else f[x]=0;
    	}
    	solve(1,1,n);
    	for(i=1;i<=n;++i)printf("%.0lf ",f[i]);
    }
    
  • 相关阅读:
    正则表达式
    c#文件流
    css
    Flash笔记 快捷键
    .Net截取指定长度的汉字,其余用...表示的方法
    远程修改最新消息管理系统(JQuery版)
    远程修改最新消息管理系统
    kubernetes 1.6 集群实践 (一)
    创建kafak集群
    创建zookeeper集群
  • 原文地址:https://www.cnblogs.com/Y-B-X/p/15521255.html
Copyright © 2011-2022 走看看