• [HDU5956]The Elder


    题面在这里

    题意

    一个王国中的所有城市构成了一棵有根树,其根节点为首都,编号为1
    树有边权,城市的记者每次向祖先移动(d)的路程需要的代价为(d^2)
    如果祖先不是根还需要加上(p),求每个非根节点的记者移动到首都的最小代价

    sol

    考虑朴素的DP,设(f[i])表示第(i)号节点到达根节点的最小代价,
    (s[i])表示(i)到根节点的距离,那么有

    [f[i]=min_{jin ancestor(i)}(f[j]+(s[i]-s[j])^2+p) ]

    初始状态为(f[1]=-p)

    斜率优化:

    [f[i]=min_{jin ancestor(i)}(f[j]+s[j]^2-2s[i]s[j])+s[i]^2+p ]

    那么考虑插点((2s[j],f[j]+s[j]^2)),询问斜率(k_i=s[i]);

    树上斜率优化——可持久化单调队列

    由于是在树上做,那么我们需要支持撤销前一次的操作;
    我们对于记录一个栈,记录推到这个节点时弹出了哪些节点,
    撤回的时候在队列中删掉当前节点,把之前弹出的节点放回去即可
    这样的时间复杂度应该仍为(O(n))

    代码

    #include<bits/stdc++.h>
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<iomanip>
    #include<cstring>
    #include<complex>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<set>
    #define mp make_pair
    #define pub push_back
    #define puf push_front
    #define pob pop_back
    #define pof pop_front
    #define RG register
    #define il inline
    using namespace std;
    typedef unsigned long long ull;
    typedef vector<int>VI;
    typedef long long ll;
    typedef double dd;
    const dd eps=1e-10;
    const int mod=1e8;
    const int N=1000010;
    il ll read(){
    	RG ll data=0,w=1;RG char ch=getchar();
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
    	return data*w;
    }
    
    il void file(){
    	freopen(".in","r",stdin);
    	freopen(".out","w",stdout);
    }
    
    ll T,n,p,f[N],s[N];
    int head[N],nxt[N<<1],to[N<<1],val[N<<1],cnt;
    il void add(ll u,ll v,ll w){
    	to[++cnt]=v;
    	nxt[cnt]=head[u];
    	val[cnt]=w;
    	head[u]=cnt;
    }
    
    int L=1,R;ll qx[N],qy[N];
    int cal[N],top;ll calx[N],caly[N];
    il void cancel(int u){
    	R--;
    	while(cal[top]==u){
    		R++;qx[R]=calx[top];qy[R]=caly[top];top--;
    	}
    }
    
    il void insert(int u,ll x,ll y){
    	while(L<R&&(qy[R]-qy[R-1])*(x-qx[R])>=(y-qy[R])*(qx[R]-qx[R-1])){
    		cal[++top]=u;calx[top]=qx[R];caly[top]=qy[R];R--;
    	}
    	R++;qx[R]=x;qy[R]=y;
    }
    
    il int check(ll k,int mid){
    	if(mid!=R&&k*(qx[mid+1]-qx[mid])>qy[mid+1]-qy[mid])
    	    return 1;
    	if(mid!=L&&k*(qx[mid]-qx[mid-1])<qy[mid]-qy[mid-1])
    	    return -1;
    	return 0;
    }
    //二分斜率
    il ll query(ll k){
    	RG int l=L,r=R,mid,ret;
    	while(l<=r){
    		mid=(l+r)>>1;
    		ret=check(k,mid);
    		if(!ret)return qy[mid]-k*qx[mid];
    		else if(ret==1)l=mid+1;
    		else if(ret==-1)r=mid-1;
    	}
    }
    
    void dfs_DP(int u,int fa){
    	if(u!=1){
    		f[u]=query(s[u])+s[u]*s[u]+p;
    		insert(u,2*s[u],f[u]+s[u]*s[u]);
    	}
    	else insert(u,0,-p);
    	for(RG int i=head[u];i;i=nxt[i]){
    		RG int v=to[i];if(v==fa)continue;
    		s[v]=s[u]+val[i];dfs_DP(v,u);
    	}
    	cancel(u);
    }
    
    il void solve(){
    	memset(head,0,sizeof(head));cnt=0;L=1;R=0;
    	n=read();p=read();
    	RG ll u,v,w;
    	for(RG int i=1;i<n;i++){
    		u=read();v=read();w=read();
    		add(u,v,w);add(v,u,w);
    	}
    
    	dfs_DP(1,0);
    	
    	RG ll maxn=0;
    	for(RG int i=1;i<=n;i++)
    		maxn=max(maxn,f[i]);
    	printf("%lld
    ",maxn);
    }
    
    int main()
    {
    	T=read();while(T--)solve();return 0;
    }
    
    
  • 相关阅读:
    电脑连不上网
    decompiler of java
    emmmmmmmmmmmmmmmmmm01
    WEB-INF
    tan?
    spring配置
    maven安装和使用前的几个点
    ※剑指offer系列29:两个链表的第一个公共结点
    剑指offer系列28:数组中的逆序对
    剑指offer系列27:第一个只出现一次的字符
  • 原文地址:https://www.cnblogs.com/cjfdf/p/8671890.html
Copyright © 2020-2023  润新知