Codeforces 题目传送门 & 洛谷题目传送门

神仙题 %%%

首先考虑对这个奇奇怪怪的 \(t^{3/2}\) 进行一番观察。考虑构造函数 \(f(x)=ax^{3/2}+b(d-x)^{3/2}\),其中 \(a,b,d\) 为参数,将其求个导 \(f'(x)=\dfrac{3}{2}(ax^{1/2}-b(d-x)^{1/2})\),不难发现 \(f'(0)=-\dfrac{3}{2}b\sqrt{d}<0,f'(d)=\dfrac{3}{2}a\sqrt{d}>0\),而在 \([0,d]\) 中随着 \(x\) 的增大,\(ax^{1/2}\) 随之增大,\(b(d-x)^{1/2}\) 随之减小,故 \(f'(x)\) 在 \([0,d]\) 中为严格增函数,即 \(\exist x_0\in[0,d],f'(x_0)=0\),故 \(f(x)\) 在 \([0,d]\) 中为严格下凸函数

这能给我们什么启示呢?考虑将这东西与树联系起来,对于树上任意一条边 \((u,v)\),假设 \(w_u=a,w_v=b\),边的距离为 \(d\),并且我们这个带权重心不一定刚好落在顶点上——它可以落在任意一条边的任意一点,那么假设我们取了 \((u,v)\) 边上一点,距离 \(u\) 为 \(x\),这样 \(u,v\) 两点的权值之和恰好就是上文中提到的函数 \(f(x)\),而 \(f(x)\) 为严格下凸函数可知必定存在 \((u,v)\) 上一点 \(t\),使得当我们将重心定在 \(t\) 时候,\(u,v\) 两点贡献的权值之和最小,并且离 \(t\) 越远,\(u,v\) 两点贡献的权值之和最大

将这个结论扩展到整棵树依旧成立,我们还是假设重心可以落在任意一条边的任意一点,那么对于重心 \(G\),我们在不断远离 \(G\) 的过程中,所有点贡献权值之和必然是不断增大的;反之当我们不断靠近 \(G\) 的过程中所有点贡献的权值之和必然是不断减小的。或者说得更通俗些,现在有一枚棋子,摆放在树的任意一个位置,我们现在要沿着树上的边移动这枚棋子,那么上述结论说的是这样一件事:如果我们正在将这枚棋子向 \(G\) 的方向移动,那么权值之和是处于不断减小的过程中,否则权值之和是处于不断增大的过程中。

我们就考虑根据这个“移动棋子”的思想解决这道题。我们假设现在有一枚棋子摆放在 \(u\) 号节点,对于 \(u\) 的任意一个邻居 \(v\),我们考虑将 \(u\) 沿着 \(v\) 的方向移动会产生什么影响,我们假设 \(u\) 沿着 \(v\) 方向移动了 \(x\) 的距离,\(u\) 到每个节点 \(v\) 的距离为 \(d_v\),那么显然移动完之和权值之和 \(g_v(x)=\sum\limits_{t\in\text{subtree}(v)}a_t(d_t-x)^{3/2}+\sum\limits_{t\notin\text{subtree}(v)}a_t(d_t+x)^{3/2}\)。我们还可以注意到 \(x=0\) 时 \(g_v(x)\) 的值就是将重心定在 \(u\) 点时的权值,而假设重心 \(G\) 就在 \(v\) 的子树(含 \((u,v)\) 的边上),根据上面的结论有我们将 \(u\) 移动到 \(v\) 的过程中权值呈现减小的趋势,那么必然有 \(g_v(0)\) 的瞬时变化量为负,将 \(g_v(x)\) 求个导可得 \(g_v'(x)=-\sum\limits_{t\in\text{subtree}(v)}\dfrac{3}{2}a_t(d_t-x)^{1/2}-\sum\limits_{t\notin\text{subtree}(v)}\dfrac{3}{2}a_t(d_t+x)^{1/2}\),我们对于每个 \(v\) 进行一遍 DFS 求出 \(g'_v(0)\) 的值,然后找到 \(g_v'(0)<0\) 的 \(v\) 并将棋子移动到 \(v\) 即可,根据之前的推论这样的 \(v\) 是唯一的。

这样复杂度是平方的,过不去,等同于暴力。不过考虑有个东西叫点分治,假设我们预期将棋子移动到 \(v\) 的位置,那么我们可以确定重心一定在 \(v\) 的子树(包括 \((u,v)\) 的边上),我们就每次找出 \(v\) 子树的重心 \(G\)(这里的重心就是普通的重心分治里的重心),将棋子移动到 \(G\) 即可,根据重心分治的复杂度可知这样是 \(n\log n\) 的。

最后注意要每移动一次更新一次答案,不要直接输出最后一次到达的位置。

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=2e5;
const int INF=0x3f3f3f3f;
int n,a[MAXN+5],hd[MAXN+5],to[MAXN*2+5],nxt[MAXN*2+5],val[MAXN*2+5],ec=0;
void adde(int u,int v,int w){to[++ec]=v;val[ec]=w;nxt[ec]=hd[u];hd[u]=ec;}
bool vis[MAXN+5];int siz[MAXN+5],mx[MAXN+5],cent=0;
int ans=0;double mn=1e25,sum[MAXN+5],sum1=0,sum2=0;
void findcent(int x,int f,int totsiz){
mx[x]=0;siz[x]=1;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(y==f||vis[y]) continue;
findcent(y,x,totsiz);siz[x]+=siz[y];
chkmax(mx[x],siz[y]);
} chkmax(mx[x],totsiz-siz[x]);
if(mx[x]<mx[cent]) cent=x;
}
void calc(int x,int f,int rt,int dep){
sum1+=1.0*a[x]*dep*sqrt(dep);
sum2+=1.0*a[x]*sqrt(dep)*3/2;
sum[rt]+=1.0*a[x]*sqrt(dep)*3/2;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e],z=val[e];if(y==f) continue;
calc(y,x,rt,dep+z);
}
}
void divcent(int x){
if(vis[x]) return;vis[x]=1;sum1=sum2=0;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e],z=val[e];sum[y]=0;calc(y,x,y,z);
}
if(sum1<mn) mn=sum1,ans=x;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e],z=val[e];
if(sum2-sum[y]*2.0<0){
cent=0;findcent(y,x,siz[y]);divcent(cent);
return;
}
}
}
int main(){
scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1,u,v,w;i<n;i++) scanf("%d%d%d",&u,&v,&w),adde(u,v,w),adde(v,u,w);
mx[0]=INF;cent=0;findcent(1,0,n);divcent(cent);
printf("%d %.15lf\n",ans,mn);
return 0;
}

Codeforces 566C - Logistical Questions(点分治)的更多相关文章

  1. 【CF566C】Logistical Questions 点分

    [CF566C]Logistical Questions 题意:给你一棵n个点的树,点有点权,边有边权,两点间的距离为两点间的边权和的$3\over 2$次方.求这棵树的带权重心. $n\le 200 ...

  2. Codeforces 833D Red-Black Cobweb [点分治]

    洛谷 Codeforces 思路 看到树上路径的统计,容易想到点分治. 虽然只有一个限制,但这个限制比较麻烦,我们把它拆成两个. 设黑边有\(a\)条,白边有\(b\)条,那么有 \[ 2a\geq ...

  3. Codeforces 1045G AI robots [CDQ分治]

    洛谷 Codeforces 简单的CDQ分治题. 由于对话要求互相看见,无法简单地用树套树切掉,考虑CDQ分治. 按视野从大到小排序,这样只要右边能看见左边就可以保证互相看见. 发现\(K\)固定,那 ...

  4. Codeforces 848C Goodbye Souvenir [CDQ分治,二维数点]

    洛谷 Codeforces 这题我写了四种做法-- 思路 不管做法怎样,思路都是一样的. 好吧,其实不一样,有细微的差别. 第一种 考虑位置\(x\)对区间\([l,r]\)有\(\pm x\)的贡献 ...

  5. Codeforces 938G Shortest Path Queries [分治,线性基,并查集]

    洛谷 Codeforces 分治的题目,或者说分治的思想,是非常灵活多变的. 所以对我这种智商低的选手特别不友好 脑子不好使怎么办?多做题吧-- 前置知识 线性基是你必须会的,不然这题不可做. 推荐再 ...

  6. Codeforces 526F Pudding Monsters - CDQ分治 - 桶排序

    In this problem you will meet the simplified model of game Pudding Monsters. An important process in ...

  7. Codeforces 448C Painting Fence:分治

    题目链接:http://codeforces.com/problemset/problem/448/C 题意: 有n个木板竖着插成一排栅栏,第i块木板高度为a[i]. 你现在要将栅栏上所有地方刷上油漆 ...

  8. Sereja and Brackets CodeForces - 380C (线段树+分治思路)

    Sereja and Brackets 题目链接: CodeForces - 380C Sereja has a bracket sequence s1, s2, ..., *s**n, or, in ...

  9. Codeforces 986D Perfect Encoding FFT 分治 高精度

    原文链接https://www.cnblogs.com/zhouzhendong/p/9161557.html 题目传送门 - Codeforces 986D 题意 给定一个数 $n(n\leq 10 ...

随机推荐

  1. MySQL:补充知识

    MySQL补充知识 在学习完 MySQL 基础与提高内容后: 基础知识笔记: MySQL:基础语法-1 MySQL:基础语法-2 MySQL:基础语法-3 MySQL:基础语法-4 提高知识笔记: M ...

  2. ruby基本图片上传

    图片上传问题 在我们的项目里,需要实现海报的图片上传,便于更好地向外界展示一个社团活动的基本内容,但是在处理中间件相关问题时遇到了一点小小的挫折.不过这并不要紧,OSS对象存储服务固然好,但是本着交完 ...

  3. BUAA_2020_软件工程_热身作业

    项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任建) 这个作业的要求在哪里 热身作业要求 我在这个课程的目标 了解软件工程的技术,掌握工程化开发的能力 这个作业在哪个具体方面 ...

  4. Spring Cloud Alibaba 的服务注册与发现

    Spring Cloud Alibaba 服务发现例子 一.需求 1.提供者完成的功能 2.消费者完成的功能 3.可以附加的额外配置 二.实现步骤 1.总的依赖引入 2.服务提供者和发现者,引入服务发 ...

  5. mongodb的索引操作

    在mongodb中,当我们一个集合中的数据量非常大时,比如几百万条数据,如果不使用索引,对数据的查询就会进行全表扫描,这个时候查询的速度就会非常的慢,此时我们就需要为集合建立上索引,从而加快查询的速度 ...

  6. MyBatis源码分析(二):MyBatis整体架构及原理

    一.Mybatis整体架构导图 二.Mybatis的核心组成 SqlSessionFactoryBuilder(构造器): 根据配置信息(XML)生成SqlSessionFactory工厂接口,构造器 ...

  7. Go并发编程--Mutex/RWMutex

    目录 一.前言 二. Mutex 2.1 案例 三. 实现原理 3.1 锁的实现模式 3.2 Go Mutex 实现原理 3.2.1 加锁 3.2.2 解锁 四. 源码分析 4.1 Mutex基本结构 ...

  8. GDI+图形图像技术1

    System.Drawing命名空间提供了对GDI+基本图形功能的访问,其中一些子命名空间中提供了更高级的功能. GDI+由GDI发展而来,是Windows图形显示程序与实际物理设备之间的桥梁. GD ...

  9. linux 内核源代码情景分析——地址映射的全过程

    linux 内核采用页式存储管理.虚拟地址空间划分成固定大小的"页面",由MMU在运行时将虚拟地址映射成某个物理内存页面中的地址.页式内存管理比段式内存管理有很多好处,但是由于In ...

  10. JuiceFS CSI Driver 的最佳实践

    文章根据 Juicedata 工程师朱唯唯,在云原生 Meetup 杭州站所作主题演讲<JuiceFS CSI Driver 的最佳实践>整理而成. 大家好,我是来自 Juicedata ...