不知哪个OJ 小x游世界树 换根?不知。

小x游世界树

(yggdrasi.pas/c/cpp)

【问题描述】

小x得到了一个(不可靠的)小道消息,传说中的神岛阿瓦隆在格陵兰海的某处,据说那里埋藏着亚瑟王的宝藏,这引起了小x的好奇,但当他想前往阿瓦隆时发现那里只有圣诞节时才能到达,然而现在已经春天了,不甘心的他将自己的目的地改成了世界树,他耗费了大量的时间,终于将自己传送到了世界树下。世界树是一棵非常巨大的树,它有着许许多多的枝条以及节点,每个节点上都有一个平台。好不容易来到传说中的世界树下,小x当然要爬上去看看风景。小x每经过一条边都会耗费体力值。然而世界树之主想给他弄(gáo)些(dǐan)麻(shì)烦(qíng),

于是他在每条边上都设了一个魔法阵,当小x踏上那条边时会被传送回根节点,魔法阵只生效一次。这岂不是要累死小x?

幸运的是,每个平台上都有无数个加速器,这些加速器可以让小x在当前节点所连的边上耗费的体力值减少,不同平台的加速器性能不一定相同,但同一个平台的加速器性能绝对相同。

世界树之主给了小x一次“换根”的机会,他可以将世界树的任何一个节点变为根,但所有的边都不能改变。小x想问你,将根换为哪个节点能使小x爬到世界树上的每个节点耗费的体力值和最少。默认编号为1的点为初始根。

【输入】

第一行一个数n,表示有n个节点。

第二行n个数ai,表示每个平台上的加速器的性能。

第三至n+1行,每行三个数bi,ci,di分别表示这条无向边的起点,终点与耗费的能量值

【输出】

第一行一个数,表示要换成的节点,如果有多个点为根时耗费的体力值都最小,则输出编号最小的那个。如果保持为1是最优的,就输出1。

第二行一个数,表示最小耗费的体力值。

【输入输出样例1】


4

2 1 3 3

1 2 3

1 3 4

2 4 6


1

9

【数据范围】

对于20%的数据:n<=100

对于40%的数据:n<=1000

对于60%的数据:n<=8000

对于80%的数据:n<=100000

对于100%的数据:0<n<=700000;ai<=1000;1<=bi,ci<=n;di<=1000。

数据保证一个点的加速器性能绝对小于等于它的所有的边所耗费的能量,保证所有节点都可以到达,保证没有数据与样例相同。

【样例解释】

如果以第一个点为根,则需要耗费0(到1)+1(到2)+2(到3)+6(到4)=9的能量值。

如果以第二个点为根,则需要耗费2(到1)+0(到2)+4(到3)+5(到4)=11的能量值。

如果以第三个点为根,则需要耗费1(到1)+2(到2)+0(到3)+7(到4)=10的能量值。

如果以第四个点为根,则需要耗费5(到1)+3(到2)+7(到3)+0(到4)=15的能量值。

很明显以第一个点为根是最优的。

好吧很明显的树上操作。。。考试是不知刚开始打了写什么辣鸡玩意QWQ

先求出来以1(随便哪个都行)为根的代价,具体地,把他当作根,做一遍dfs,每条边的贡献是(w(u,v)-a[u])*size[v];

然后主要就是在树上如何转移:由u到v时,当前的cost(cost初值是以1为根的代价)-= (w(u,v)-a[u])*size[v] 再+=(w(u,v)-a[v])*(sz[1]-sz[v]),相当于是原来是从u到v,现在是从v到u,回溯时反向操作。

然后更新答案时记得加上字典序的比较,否则会死(亲身经历QWQ)

#include<cstdio>
#include<iostream>
#define ll long long
#define R register ll
using namespace std;
const int N=700010;
inline int g() {
    R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch==‘-‘?-1:fix;
    do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
}
int n,cnt,ccnt,anss;
int vr[N<<1],nxt[N<<1],w[N<<1],fir[N],sz[N],a[N];
ll cost,ans=1E+15;
inline void add(int u,int v,int ww) {vr[++cnt]=v,w[cnt]=ww,nxt[cnt]=fir[u],fir[u]=cnt;}
inline void dfsdown(int u,int fa) { sz[u]=1;
    for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
        if(v==fa) continue;
        dfsdown(v,u); sz[u]+=sz[v]; cost+=(w[i]-a[u])*sz[v];
    }
}
inline void solve(int u,int fa) {
    if(ans>cost||(ans==cost&&anss>u)) anss=u,ans=cost;
    for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
        if(v==fa) continue;
        cost-=(w[i]-a[u])*sz[v],cost+=(w[i]-a[v])*(sz[1]-sz[v]); solve(v,u);
        cost+=(w[i]-a[u])*sz[v],cost-=(w[i]-a[v])*(sz[1]-sz[v]);
    }
}
signed main() { freopen("yggdrasil.in","r",stdin); freopen("out.out","w",stdout);
    n=g(); for(R i=1;i<=n;++i) a[i]=g();
    for(R i=1,u,v,w;i<n;++i)  u=g(),v=g(),w=g(),add(u,v,w),add(v,u,w);
    dfsdown(1,0); solve(1,0); printf("%d\n%lld\n",anss,ans);
} 


因为听了BK老师的课而自闭了几天。。。今天考试智商下降体现在下一题上。。。QWQ2019.05.04

原文地址:https://www.cnblogs.com/Jackpei/p/10808723.html

时间: 2024-10-11 00:40:10

不知哪个OJ 小x游世界树 换根?不知。的相关文章

JZOJ5776 小x游世界树

Description 小x得到了一个小道消息,传说中的神岛阿瓦隆在格陵兰海的某处,据说那里埋藏着亚瑟王的宝藏,这引起了小x的好奇,但当他想前往阿瓦隆时发现那里只有圣诞节时才能到达,然而现在已经春天了,不甘心的他将自己的目的地改成了世界树,他耗费了大量的时间,终于将自己传送到了世界树下.世界树是一棵非常巨大的树,它有着许许多多的枝条以及节点,每个节点上都有一个平台.好不容易来到传说中的世界树下,小x当然要爬上去看看风景.小x每经过一条边都会耗费体力值.然而世界树之主想给他弄(gáo)些(dǐan

小x游世界树

题源 Input 7 7 8 1 3 2 5 2 4 6 5 6 1 8 1 2 9 5 4 3 3 4 10 3 7 4 Output 1 24 一看就知道是个什么套路 记录每个点的siz , dis.在父子节点间考虑转移. 然后搞了个代码,过了个极水的样例 1 #include<stdio.h> 2 #define For(i,a,b) for(register int i=(a);i<=(b);i++) 3 using namespace std; 4 const int maxn

newcoder 79F 小H和圣诞树 换根 DP + 根号分治

Code: #include <cstdio> #include <algorithm> #include <vector> #include <cmath> #include <map> #define N 100003 #define ll long long #define setIO(s) freopen(s".in", "r" , stdin) , freopen(s".out"

换根dp「小奇的仓库&#183;randomwalking&#183;」

把以前考试换根题集中写一下 随便选一个点做根一遍$dfs$求子树内贡献,再通过特殊手段算$ans[1]$,最后$dfs$求其他$ans$ 拆成子树内,子树外分别算贡献差,得儿子是很常见套路了 小奇的仓库 $M<=15$ 题解 很久之前做的换根dp,当时觉得真是神仙,现在看还是觉得很神仙 不同于一般换根dp,这个题$n^2$并不好写 所以$n^2$算法就省略了 考虑$M$非常小,可以计算$M$对答案影响 一个直接的想法是先算出来原答案,再减去现在答案 //本来为j现在异或M,变化了j-delta

poj3585树最大流——换根法

题目:http://poj.org/problem?id=3585 二次扫描与换根法,一次dfs求出以某个节点为根的相关值,再dfs遍历一遍树,根据之前的值换根取最大值为答案. 代码如下: #include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,head[200005],ct,d[200005],f[200005],deg[200005],ans,t; bool v

遥远的国度(树链剖分,换根)

遥远的国度 题目描述 zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀. 问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树.这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的.遥远的国度的每个城市有一个防御值,有些时候RapiD会使

POJ3585 换根模板

题意:机翻? 好,假装各位都已经看懂了题. 首先是暴力,枚举每一个点作为根,然后每次做一个树上DP,复杂度O(n2),T掉: 然后,我们考虑怎样优化. 假设我们已经求出了x的答案,对与每一个它的子节点, 我们注意到其实当我们换其子节点y为根时,y的子树贡献是已知的. 只需考虑另外一侧的贡献之间, 同时又注意到,除y以外的对x的贡献就是x的答案减掉y对它的贡献,也是一定的. 所以只有x会影响到y,直接根据限制在y和x之间转移一下就好了. #include <cstdio> #include &l

cf219d 基础换根法

/*树形dp换根法*/ #include<bits/stdc++.h> using namespace std; #define maxn 200005 struct Edge{int to,nxt,flag;}edge[maxn<<1]; int root,n,s,t,head[maxn],tot,dp[maxn]; void init(){ memset(head,-1,sizeof head); tot=0; } void addedge(int u,int v,int fl

题解 poj3585 Accumulation Degree (树形dp)(二次扫描和换根法)

写一篇题解,以纪念调了一个小时的经历(就是因为边的数组没有乘2 phhhh QAQ) 题目 题目大意:找一个点使得从这个点出发作为源点,流出的流量最大,输出这个最大的流量. 以这道题来介绍二次扫描和换根法 作为一道不定根的树形DP,如果直接对每个点进行DP,可能时间会炸掉 但是,优秀的二次换根和扫描法可以再O(n^2)内解决问题. 二次扫描的含义:(来自lyd 算法竞赛进阶指南) 第一次扫描:任选一个节点为根节点(我会选1)在树上进行树形DP,在回溯时,从儿子节点向父节点(从底向上)进行状态转移