枚举每条树边,将其断开,那么两侧肯定取带权重心最优。

考虑如何求出每个子树的重心,枚举其所有儿子,通过重量关系就可以判断出重心位于哪棵子树。

然后将那棵子树的重心暴力往上爬即可,因为每个点作为重心肯定是一段连续的链,所以复杂度为$O(n)$。

然后就是如何求出砍掉每棵子树之后剩下的部分的重心。

设当前点到根的路径为关键路径,那么可以通过二分求出重心在关键路径上哪个点的子树里。

对于那棵子树,重心要么是它本身,要么在它最重的子树里,要么在次重的子树里。

在线段树上按dfs序维护区间内子树重量的最大值,即可用线段树完成重心的查询,时间复杂度$O(\log n)$。

总时间复杂度$O(n\log n)$。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=500010,BUF=12000000;
char Buf[BUF],*buf=Buf;
int n,i,x,y,w[N],g[N],v[N<<1],nxt[N<<1],ed;
int f[N],d[N],size[N],son[N],top[N],st[N],en[N],id[N],dfn,q[N],cq;
int fir[N],sec[N],center[N],vip[N];
ll sum[N],sw[N],val[1050000],sd[N],su[N],ans=1LL<<60;
inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;}
inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
void dfs(int x){
size[x]=1;
for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
f[v[i]]=x,d[v[i]]=d[x]+1;
dfs(v[i]),size[x]+=size[v[i]];
if(size[v[i]]>size[son[x]])son[x]=v[i];
}
}
void dfs2(int x,int y){
id[st[x]=++dfn]=x;top[x]=y;
if(son[x])dfs2(son[x],y);
for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);
en[x]=dfn;
}
inline int dis(int x,int y){
int t=d[x]+d[y];
for(;top[x]!=top[y];x=f[top[x]])if(d[top[x]]<d[top[y]])swap(x,y);
if(d[x]>d[y])swap(x,y);
return t-2*d[x];
}
inline void cal(int x){
int i=center[fir[x]];
ll t=sum[fir[x]]+sd[x]-sd[fir[x]]-sw[fir[x]]+(sw[x]-sw[fir[x]])*(d[i]-d[x]);
while(2*sw[i]<sw[x])t+=2*sw[i]-sw[x],i=f[i];
center[x]=i;
sum[x]=t;
}
void dfs3(int x){
sw[x]=w[x];
for(int i=g[x];i;i=nxt[i]){
int y=v[i];
if(y==f[x])continue;
dfs3(y);
sw[x]+=sw[y];
if(sw[y]>sw[fir[x]])sec[x]=fir[x],fir[x]=y;
else if(sw[y]>sw[sec[x]])sec[x]=y;
sd[x]+=sd[y]+sw[y];
}
if(2*sw[fir[x]]<=sw[x]){
center[x]=x;
sum[x]=sd[x];
return;
}
cal(x);
}
void dfs4(int x){
if(f[x]){
int y=f[x];
su[x]=su[y]+sd[y]-sd[x]-2*sw[x]+sw[1];
}
for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x])dfs4(v[i]);
}
inline int lower(ll x){
int l=2,r=cq,mid,t=1;
while(l<=r)if(2*(sw[q[mid=(l+r)>>1]]-x)>=sw[1]-x)l=(t=mid)+1;else r=mid-1;
return q[t];
}
void build(int x,int a,int b){
if(a==b){val[x]=sw[id[a]]*2;return;}
int mid=(a+b)>>1;
build(x<<1,a,mid),build(x<<1|1,mid+1,b);
val[x]=max(val[x<<1],val[x<<1|1]);
}
int ask(int x,int a,int b,int c,int d,ll p){
if(val[x]<p)return 0;
if(a==b)return a;
int mid=(a+b)>>1,t=0;
if(d>mid)t=ask(x<<1|1,mid+1,b,c,d,p);
if(t)return t;
if(c<=mid)t=ask(x<<1,a,mid,c,d,p);
return t;
}
void dfs5(int x){
if(f[x])vip[x]=lower(sw[x]);
q[++cq]=x;
for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x])dfs5(v[i]);
cq--;
}
inline void solve(int x){
int t=vip[x],y,z=0;
if(st[fir[t]]<=st[x]&&en[x]<=en[fir[t]])y=sec[t];else y=fir[t];
if(y)z=ask(1,1,n,st[y],en[y],sw[1]-sw[x]);
if(!z)z=t;else z=id[z];
ans=min(ans,sum[x]+sd[z]+su[z]-sd[x]-sw[x]*dis(x,z));
}
int main(){
fread(Buf,1,BUF,stdin);read(n);
for(i=1;i<n;i++)read(x),read(y),add(x,y),add(y,x);
for(i=1;i<=n;i++)read(w[i]);
dfs(1);dfs2(1,1);
dfs3(1);dfs4(1);
build(1,1,n);dfs5(1);
for(i=2;i<=n;i++)solve(i);
return printf("%lld",ans),0;
}

  

BZOJ3068 : 小白树的更多相关文章

  1. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  2. Bzoj 1756: Vijos1083 小白逛公园 线段树

    1756: Vijos1083 小白逛公园 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1021  Solved: 326[Submit][Statu ...

  3. Vijos 1083 小白逛公园(线段树)

    线段树,每个结点维护区间内的最大值M,和sum,最大前缀和lm,最大后缀和rm. 若要求区间为[a,b],则答案max(此区间M,左儿子M,右儿子M,左儿子rm+右儿子lm). ----------- ...

  4. 线段树 || BZOJ1756: Vijos1083 小白逛公园 || P4513 小白逛公园

    题面:小白逛公园 题解: 对于线段树的每个节点除了普通线段树该维护的东西以外,额外维护lsum(与左端点相连的最大连续区间和).rsum(同理)和sum……就行了 代码: #include<cs ...

  5. 树的最长链-POJ 1985 树的直径(最长链)+牛客小白月赛6-桃花

    求树直径的方法在此转载一下大佬们的分析: 可以随便选择一个点开始进行bfs或者dfs,从而找到离该点最远的那个点(可以证明,离树上任意一点最远的点一定是树的某条直径的两端点之一:树的直径:树上的最长简 ...

  6. 洛谷 P4513 小白逛公园-区间最大子段和-分治+线段树区间合并(单点更新、区间查询)

    P4513 小白逛公园 题目背景 小新经常陪小白去公园玩,也就是所谓的遛狗啦… 题目描述 在小新家附近有一条“公园路”,路的一边从南到北依次排着nn个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩 ...

  7. 牛客网 牛客小白月赛5 I.区间 (interval)-线段树 or 差分数组?

    牛客小白月赛5 I.区间 (interval) 休闲的时候写的,但是写的心情有点挫,都是完全版线段树,我的一个队友直接就水过去了,为啥我的就超内存呢??? 试了一晚上,找出来了,多初始化了add标记数 ...

  8. 牛客小白月赛19 E 「火」烈火燎原 (思维,树)

    牛客小白月赛19 E 「火」烈火燎原 (思维,树) 链接:https://ac.nowcoder.com/acm/contest/2272/E来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空 ...

  9. [vijos]1083小白逛公园<线段树>

    描述 小新经常陪小白去公园玩,也就是所谓的遛狗啦…在小新家附近有一条“公园路”,路的一边从南到北依次排着n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了. 一开始,小白就根据公园的风景给每个公 ...

随机推荐

  1. jQuery - 1.简单的JQuery

    1.简单的JQuery 2.jQuery对象(包装集).Dom对象 3.JQuery提供的函数 1.简单的JQuery $(document).ready(function () { alert(&q ...

  2. 与你相遇好幸运,Linux常用命令

    开机挂载硬盘 cat  /etc/fstab /dev/sda1  /mnt/sda1 ext3    defaults    0  0 挂载硬盘 mount  /dev/sdb5 /home/dis ...

  3. 重温WCF之会话Session(九)

    转载地址:http://blog.csdn.net/tcjiaan/article/details/8281782 每个客户端在服务器上都有其的独立数据存储区,互不相干,就好像A和服务器在单独谈话一样 ...

  4. Algorithms, Part I by Kevin Wayne, Robert Sedgewick

    Welcome to Algorithms, Part I 前言 昨天在突然看到了Coursera上Robert Sedgewick讲的Algorithms,Part II看了一些,甚是爽快,所以又去 ...

  5. 【翻译四】java-并发之线程暂停

    Pausing Execution with Sleep Thread.sleep causes the current thread to suspend execution for a speci ...

  6. 在PYTHON3中,使用Asyncio来管理Event loop

    #!/usr/bin/env python # -*- coding: utf-8 -*- import asyncio import datetime import time def functio ...

  7. [译] Extending jQuery Part1 Simple extensions

    本章包含: JQuery 的起源和目标. 你能扩展JQuery 的那些部分. JQuery 扩展的实例. 如今,JQuery 已经是网络上最受欢迎的JavaScript Library. 1.1 jQ ...

  8. Java Hour 62 J2EE App 服务器

    目前略微瓶颈了,准备换工作. tomcat.weblogic.jboss的区别,容器的作用 Apache 是一个http 服务器. Tomcat 是一web 应用程序服务器,支持部分的j2ee. Jb ...

  9. html5移动Web开发实战

    1.解决横竖屏字体大小变化 html{ -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; text-size-adjust:100 ...

  10. 在ubuntu中安装jdk

    安装环境 操作系统:ubuntu 14.04.1 server amd64 下载jdk wget http://download.oracle.com/otn-pub/java/jdk/7u67-b0 ...