BZOJ3302: [Shoi2005]树的双中心

n<=50000的树,深度<=100,有点权,选两个点x,y,使最小。

dis取了min之后,整个树就会以某条边为分界线分成两半,一半归一个点管。如果是两棵完全独立的树的话,那肯定分别取这两棵树的带权重心。但割掉某条边再找两边重心,这种情况不一定是合法情况。例如:

上图中,虚线边被断开,两边的重心分别是星标节点。这不是一个合法方案,但它显然不如一个合法方案的答案优:

所以放心大胆地割就好了。注意到本题中树的深度h很小,所以割边后涉及的子树信息修改操作都可以暴力修改。

把树以某点为根,希望能预处理出一些信息使得能够在O(h)的时间内找到割完边每一半的重心。如果是普通的一棵树,知道了子树大小(权值和)之后,从某点出发最多走2h步之后就可以到重心。割了某条边之后,一个点最多只会有一棵子树信息被修改。因此记最大儿子和次大儿子即可。

至于答案的记录我写的有点丑。如果想的话可以看一下我怎么写的,不然就直接看怎么写更方便吧。所有子树大小加起来即为根节点为重心的总代价,因为这样加起来,越是下面的点加的次数越多。断掉某条边之后,修改子树大小的同时可修改根节点为重心答案,然后从根节点开始向重儿子走,只要比较最大儿子和次大儿子子树权和即可,边走边改答案。走一步,就是走到的这棵子树权值和少算一次,其外面的权值和多算一次。

我是记了每个节点为根的答案。。式子有点乱。。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h>
 4 #include<algorithm>
 5 //#include<queue>
 6 //#include<iostream>
 7 using namespace std;
 8
 9 int t,n;
10 #define maxn 50011
11 struct Edge{int to,next;}edge[maxn<<1];int first[maxn],le,val[maxn];
12 void in(int x,int y) {Edge &e=edge[le];e.to=y;e.next=first[x];first[x]=le++;}
13 void insert(int x,int y) {in(x,y);in(y,x);}
14 void init()
15 {
16     scanf("%d",&n);
17     memset(first,0,sizeof(first));le=2;
18     int x,y;
19     for (int i=1;i<n;i++)
20     {
21         scanf("%d%d",&x,&y);
22         insert(x,y);
23     }
24     for (int i=1;i<=n;i++) scanf("%d",&val[i]);
25 }
26 #define LL long long
27 int size[maxn],dep[maxn],f[maxn],tot,hea[maxn],h2[maxn];LL aa[maxn];
28 void dfs(int x,int fa)
29 {
30     size[x]=val[x];dep[x]=dep[fa]+1;f[x]=fa;tot+=val[x];
31     hea[x]=h2[x]=0;aa[x]=0;
32     for (int i=first[x];i;i=edge[i].next)
33     {
34         const Edge &e=edge[i];if (e.to==fa) continue;
35         dfs(e.to,x);size[x]+=size[e.to];
36         aa[x]+=aa[e.to]+size[e.to];
37         if (size[e.to]>size[hea[x]]) h2[x]=hea[x],hea[x]=e.to;
38         else if (size[e.to]>size[h2[x]]) h2[x]=e.to;
39     }
40 }
41 int main()
42 {
43         init();
44         tot=0;dfs(1,0);
45         LL ANS=1e15;
46         for (int i=2;i<le;i+=2)
47         {
48             int x=edge[i].to,y=edge[i^1].to;
49             if (dep[x]<dep[y]) {int t=x;x=y;y=t;}
50             for (int i=f[x],cnt=1;i;i=f[i],cnt++) size[i]-=size[x],aa[i]-=aa[x]+1ll*cnt*size[x];
51             tot-=size[x];
52             LL ans=0,qq=0;
53             for (int now=1;;)
54             {
55                 int tmp=(hea[now]==x?(h2[now]?size[h2[now]]:0):(h2[now]==x?size[hea[now]]:
56                 max(size[hea[now]],size[h2[now]])))*2;
57
58                 if (tmp<=tot) {ans+=aa[now]+qq;break;}
59                 if (size[hea[now]]>size[h2[now]] && hea[now]!=x) now=hea[now],
60                 qq+=aa[f[now]]-(aa[now]+size[now])+tot-size[now];
61                 else now=h2[now],qq+=aa[f[now]]-(aa[now]+size[now])+tot-size[now];
62             }
63             qq=0;
64             for (int now=x;;)
65             {
66                 if (size[hea[now]]*2<=size[x]) {ans+=aa[now]+qq;break;}
67                 now=hea[now],qq+=aa[f[now]]-(aa[now]+size[now])+size[x]-size[now];
68             }
69             ANS=min(ANS,ans);
70             tot+=size[x];
71             for (int i=f[x],cnt=1;i;i=f[i],cnt++) size[i]+=size[x],aa[i]+=aa[x]+1ll*cnt*size[x];
72         }
73         printf("%lld\n",ANS);
74     return 0;
75 }

时间: 2024-10-05 22:28:09

BZOJ3302: [Shoi2005]树的双中心的相关文章

【BZOJ3302】[Shoi2005]树的双中心 DFS

[BZOJ3302][Shoi2005]树的双中心 Description Input 第一行为N,1<N<=50000,表示树的节点数目,树的节点从1到N编号.接下来N-1行,每行两个整数U,V,表示U与V之间有一条边.再接下N行,每行一个正整数,其中第i行的正整数表示编号为i的节点权值为W(I),树的深度<=100 Output 将最小的S(x,y)输出,结果保证不超过19^9 Sample Input 5 1 2 1 3 3 4 3 5 5 7 6 5 4 Sample Outpu

P2726 [SHOI2005]树的双中心 题解

CSDN同步 原题链接 简要题意: 给定一棵树,\(d_{x,y}\) 为 \(x\) 与 \(y\) 距离(\(d_{x,x} = 0\)),选出两个点 \(x,y\),最小化: \[\sum_{u \in V} (w_u \times \min(dis_{x,u} , dis_{y,u})) \] 这种水的树形dp 黑题,没几个人做真是太可惜了 首先我们要明白这个式子是什么意思. \(\min (dis_{x,u} , dis_{y,u})\),就是在 \(x\) 和 \(y\) 中找到较近

DTU/RTU连接双中心配置说明

TCP模式双中心数据传输 实例说明 此实例是使用TCP模式将串口收到的数据转发到服务器上,将服务器发送的数据转发到串口中.在传输过程中不对数据进行加密. 配置服务器网络 1, 确认本机服务器的外网IP地址或域名 A,此实例以外网为固定IP专线   IP地址为220.160.156.233. B,如果外网为拨号上号的方式,就需要使用域名. 条件一: 通过花生壳或是其他域名解析终端绑定外网IP 条件二: 如果只是短时间的测试通信,可以直接使用当前外网IP 查询当前外网IP方法:用百度搜索“IP” 如

浅谈同城双中心的网络部署模型

企业建设数据中心时,出于灾备的考虑,会建设两个甚至多个数据中心.例如我们经常提到的"两地三中心",即同城双中心+异地中心. 同城双中心是指在同城或邻近城市建立两个可独立承担业务的数据中心,双中心具备基本相同的业务处理能力并通过高速链路实时同步数据,日常情况下可同时分担业务及管理系统的运行,并可切换运行:灾难情况下备应急切换,保证业务的持续性.异地灾备中心是指在异地的城市建立一个备份的灾备中心,用于双中心的数据备份,当双中心出现自然灾害等原因而发生故障时,异地灾备中心可以用备份数据进行业

[51nod]A树的双直径

题目链接: 51nod 树形\(DP\)+换根\(DP\). 最直观的想法是枚举一条边断开,在两颗子树中求最大直径相乘然后取最大值. 不过这题可能出现负数,那么答案可能是正数\(\times\)正数或者负数\(\times\)负数. 其实只需要考虑正数的情况(负数把边全部取反即可) 那么设枚举边\((x,y)\),其中\(x\)为\(y\)的父亲 那么我们需要求出以\(y\)为根子树中的最长链和除去\(x\)子树外的最长链 对于\(y\)子树中的最长链\(InMax[y]\),我们可以先考虑求出

【两地三中心】两地三中心--灾备解决方案

两地三中心,两地是指同城.异地,三中心是指生产中心.同城容灾中心.异地容灾中心.结合近年国内出现的大范围自然灾害,以同城双中心加异地灾备中心的"两地三中心"的灾备模式也随之出现,这一方案兼具高可用性和灾难备份的能力.同城双中心是指在同城或邻近城市建立两个可独立承担关键系统运行的数据中心,双中心具备基本等同的业务处理能力并通过高速链路实时同步数据,日常情况下可同时分担业务及管理系统的运行,并可切换运行:灾难情况下可在基本不丢失数据的情况下进行灾备应急切换,保持业务连续运行.与异地灾备模式

Oracle数据库中心双活之道:ASM vs VPLEX (转)

双活方案对比:ASM vs V-PLEX 作者:王文杰 Oracle公司 Principle system analyst Oracle高级服务部 Oracle数据库中心的灾备的演变,经历了多年的演变从最初的冷备份,到热备份,到存储复制,到DG,ADG,RAC one node, RAC,最终演变到了目前最炙手可热的双活双中心构架,也就是我们常说的远程RAC(Extended RAC). 一般售前工程师口中实现双活的方案有很多种,但我认为真正RTO,RPO趋近于0,且双中心可用(读写)的方案,才

理解B+树算法和Innodb索引

一.innodb存储引擎索引概述: innodb存储引擎支持两种常见的索引:B+树索引和哈希索引. innodb支持哈希索引是自适应的,innodb会根据表的使用情况自动生成哈希索引. B+树索引就是传统意义上的索引,是关系型数据库中最常用最有效的索引.B+树是从最早的平衡二叉树演变而来,但是B+树不是一个二叉树.B+中的B不代表二叉(Binary),而是代表平衡(Balance). 注意:B+树索引并不能找到一个键值对应的具体行.b+树索引只能查到被查找数据行所在的页,然后数据库通过把页读入内

信息检索——初识Trie树

1.概述 Trie树( /tri:/ ),又称前缀树.字典树,是种快速检索的多叉树结构, Trie树的基本性质可以归纳为: (1)根节点不包含字符,除根节点意外每个节点只包含一个字符. (2)从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串. (3)每个节点的所有子节点包含的字符串不相同. 2.Trie基本实现 基本操作包括插入.删除.查找等. 考虑到通常用于字典等内存较大的情况,应该加入序列化,分割等操作. 3.应用 接触这一数据结构是因为分词处理中的字典存储问题,对这一问