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. Flask的环境配置

      Flask django是大而全,提供所有常用的功能 flask是小而精,只提供核心功能 环境配置 为了防止 django和 flask环境相互冲突,可以使用 虚拟环境分割开 pip instal ...

  2. 初学python-day9 函数1(已更新)

    函数 一.函数基础 1.什么是函数 在一个完整的项目中,某些功能会被重复使用,那么会将代码段封装成函数,当我们要使用的时候,直接调用即可. 函数是可以实现一定的小程序或者功能. 优点: 增加了代码的重 ...

  3. 【UE4 设计模式】享元模式 Flyweight Pattern

    概述 描述 运用共享技术有效地支持大量细粒度对象的复用.系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用. 由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻 ...

  4. kivy画板

    from kivy.app import App from kivy.graphics import Line, Color # 引入绘图线条,颜色 from kivy.uix.widget impo ...

  5. MySQL:提高笔记-2

    MySQL:提高笔记-2 学完基础的语法后,进一步对 MySQL 进行学习,第一篇为:MySQL:提高笔记-1,这是第二篇内容 说明:这是根据 bilibili 上 黑马程序员 的课程 mysql入门 ...

  6. 软件工程个人博客作业-软件案例分析:VS与VS Code

    项目 内容 本作业属于北航 2020 年春软件工程 博客园班级连接 本作业是本课程个人项目作业 作业要求 我在这个课程的目标是 提高软件开发能力.团队协作能力 这个作业在哪个具体方面帮助我实现目标 提 ...

  7. OO--第三单元规格化设计 博客作业

    OO--第三单元规格化设计 博客作业 前言 第三单元,我们以JML为基础,先后完成了 PathContainer -> Graph -> RailwaySystem 这是一个递进的过程,代 ...

  8. websocket入门案例(echo)

    websocket是用来干什么的,具体的请自行百度. 本文实现一个简单的websocket的入门小例子,实现客户端发送一句换,服务器端返回.即一个简单的交互. 一.服务器端的实现 1.创建一个类实现S ...

  9. skywalking实现分布式系统链路追踪

    一.背景 随着微服务的越来越流行,我们服务之间的调用关系就显得越来越复杂,我们急需一个APM工具来分析系统中存在的各种性能指标问题以及调用关系.目前主流的APM工具有CAT.Zipkin.Pinpoi ...

  10. CSP踩被记

    本来想起个清新脱俗的标题,但碍于语文功底不行,于是光明正大嫖了LiBoyi的高端创意,把这篇博客命名为踩被记. Day -6 用假暴力把真正解拍没了,伤心.Rp有点低 Day -4 信息学考,\(py ...