• [ZJOI2007]时态同步


    洛咕

    题意:给定一棵(N(N<=500000))个节点的树以及树根编号,每次操作可以使得一条边的边权加1,求使得根节点到所有叶子节点距离相同需要的最少操作次数.

    分析:显然当一棵子树内的所有叶子节点到根节点的路径都需要增加边权时,给越上面的边增加边权越好.但是我们发现如果从树根往下处理,判断,加边权后的路径距离更新等等并不太好实现.

    考虑从叶子节点往上推,这也是树形DP的一般过程.为什么从叶子节点往上推会比较好处理呢,试想一棵3个节点的子树,就是一个父亲节点,下面两个儿子节点,我们只要求出两个叶子节点分别到父亲节点的距离,记为(f[i]),那么距离小的那个一定需要增加边权.也就是说从下往上推,每一步判断是否增加边权,增加多少边权,都是可以确定的.

    不开long long会WA最后两个点.

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #define ll long long
    using namespace std;
    inline int read(){
        int x=0,o=1;char ch=getchar();
        while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
        if(ch=='-')o=-1,ch=getchar();
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*o;
    }
    const int N=500005;
    ll ans,f[N];
    int tot,head[N],nxt[N*2],to[N*2],w[N*2];
    inline void add(int a,int b,int c){
    	nxt[++tot]=head[a];head[a]=tot;
    	to[tot]=b;w[tot]=c;
    }
    inline void dfs(int u,int fa){
    	for(int i=head[u];i;i=nxt[i]){
    		int v=to[i];
    		if(v==fa)continue;
    		dfs(v,u);
    		f[u]=max(f[u],f[v]+w[i]);//找到最大距离
    	}
    	for(int i=head[u];i;i=nxt[i]){
    		int v=to[i];
    		if(v==fa)continue;
    		ans+=f[u]-(f[v]+w[i]);//增加边权
    	}
    }
    int main(){
    	int n=read(),root=read();
    	for(int i=1;i<n;++i){
    		int a=read(),b=read(),c=read();
    		add(a,b,c);add(b,a,c);
    	}
    	dfs(root,0);
    	printf("%lld
    ",ans);
        return 0;
    }
    
    
  • 相关阅读:
    Vim快捷键,行首行尾
    java程序 cpu占用过高分析
    svn merge操作
    linux root用户无法删除文件,提示permission denied
    诡异问题:tomcat启动一直卡住,strace跟踪提示apache-tomcat核心文件找不到。
    转:xcode项目打不开:incompatible project version问题
    路由器当交换机用
    visual studio远程调试 remote debugger
    Sql server锁
    long 在不同操作系统下所占用的字节数
  • 原文地址:https://www.cnblogs.com/PPXppx/p/11311988.html
Copyright © 2020-2023  润新知