[cf566C]Logistical Questions

记$d(x,y)$为$x$到$y$的距离,$cost_{x}=\sum_{i=1}^{n}w_{i}d(x,i)^{\frac{3}{2}}$为$x$的代价

取$C$为足够大量,对于一条边权为$w$的边,在边上新建$wC-1$个点,这些点点权为0(即本身无影响),并将边拆成$wC$段,那么每一段边权为$\frac{1}{C}$

任取(新树中)一条路径$\{a_{1},a_{2},...,a_{l}\}$,则$cost_{a_{i}}$具有凸性

根据凸性定义,即求证$\forall 2\le j\le l-1,2cost_{a_{j}}\le cost_{a_{j-1}}+cost_{a_{j+1}}$

代入其式子,不妨对每一个$i$都保证此性质,也即求证$2d(a_{j},i)^{\frac{3}{2}}\le d(a_{j-1},i)^{\frac{3}{2}}+d(a_{j+1},i)^{\frac{3}{2}}$

对$i$的位置分类讨论:

1.$i$距离$a_{j}$最近,则$d(a_{j},i)\le d(a_{j-1},i),d(a_{j+1},i)$,显然成立

2.$i$不距离$a_{j}$最近,记$x=d(a_{j},i)$,那么即$2x^{\frac{3}{2}}\le (x-\frac{1}{C})^{\frac{3}{2}}+(x+\frac{1}{C})^{\frac{3}{2}}$

令$f(x)=x^{\frac{3}{2}}$,代入并移项,也即$f(x)-f(x-\frac{1}{C})\le f(x+\frac{1}{C})-f(x)$

当$C$足够大时,两者可以看作$\frac{f'(x)}{C}$和$\frac{f'(x+\frac{1}{C})}{C}$,注意到$f'(x)=\frac{3}{2}x^{\frac{1}{2}}$单调递增,即成立

进而考虑其中非新建的点$\{b_{1},b_{2},...,b_{k}\}$,根据$cost_{a_{i}}$的凸性,$cost_{b_{i}}$的形式必然是先严格单调递减、再有若干个相同的数(最小值)、最后严格单调递增(首尾两段允许为空)

由于(原树中)任意一条路径都可以被以此法选择,即所有路径都为此形式


(以下删去上述新建的点,即仍考虑原树)

约定$x$为质心当且仅当$\forall 1\le i\le n,cost_{x}\le cost_{i}$,题目即要找到任意一个质心即可

任取一点$x$,对与$x$相邻的点$y$,至多存在一个$y$满足$cost_{y}<cost_{x}$

(否则任取其中两个记为$y_{1}$和$y_{2}$,考虑$y_{1}$到$y_{2}$的路径即矛盾)

进一步的,再对其分类讨论:

1.如果不存在$y$满足$cost_{y}<cost_{x}$,则对于树上任意一点$z$,考虑其到$x$的路径,由于最后一步仍没有递增,根据路径的形式不难得到$cost_{x}\le cost_{z}$,也即$x$为质心

2.如果存在$y$满足$cost_{y}<cost_{x}$,那么对于以$y$为根时$x$子树中的任意一点$z$,考虑其到$y$的路径,由于最后一步严格单调递减,根据路径的形式不难得到$cost_{y}<cost_{z}$,也即$z$一定不为质心

综上,不难得到下述暴力做法——

初始连通子树$T_{0}=T$,并任取$T_{0}$中一点$x$,求出所有与$x$相邻的点$y$的答案,若不存在$y$满足$cost_{y}<cost_{x}$则$x$为质心,若存在$y$满足$cost_{y}<cost_{x}$(必然唯一)令$T_{0}$为删去$x$后$y$所在的连通块并递归即可(第二种情况,剩下的部分一定不包含质心)

如果令$x$为$T_{0}$中的重心(指通常的定义),那么每一次$T_{0}$的规模至少缩小一半,即至多$o(\log n)$层

但如果暴力计算所有$y$,仍会导致复杂度过高(每一次计算是$o(n)$的),考虑优化:

对于所有边$(x,y,w)$,在边上新建一个点,其点权为0、到$x$距离为1、到$y$距离为$w-1$

由此,只需要求出这些新建点的$cost$即可(注意其并不影响上述分析),维护(以$x$为根后)每一个新建点子树内所有点到其距离的$\frac{3}{2}$次之和、到其距离+2的$\frac{3}{2}$次之和即可

(注意虽然重心一定在$T_{0}$中,但递归的仍是整个$T$)

时间复杂度为$o(n\log n)$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 200005
 4 struct Edge{
 5     int nex,to,len;
 6 }edge[N<<1];
 7 int n,E,rt,x,y,z,a[N],head[N],sz[N],vis[N];
 8 void add(int x,int y,int z){
 9     edge[E]=Edge{head[x],y,z};
10     head[x]=E++;
11 }
12 void get_sz(int k,int fa){
13     sz[k]=1;
14     for(int i=head[k];i!=-1;i=edge[i].nex)
15         if ((!vis[edge[i].to])&&(edge[i].to!=fa)){
16             get_sz(edge[i].to,k);
17             sz[k]+=sz[edge[i].to];
18         }
19 }
20 void get_rt(int k,int fa,int s){
21     int mx=s-sz[k];
22     for(int i=head[k];i!=-1;i=edge[i].nex)
23         if ((!vis[edge[i].to])&&(edge[i].to!=fa)){
24             get_rt(edge[i].to,k,s);
25             mx=max(mx,sz[edge[i].to]);
26         }
27     if (mx<=(s>>1))rt=k;
28 }
29 double get_s(int k,int fa,int s){
30     double sum=a[k]*(pow(s,1.5)-pow(s+2,1.5));
31     for(int i=head[k];i!=-1;i=edge[i].nex)
32         if (edge[i].to!=fa)sum+=get_s(edge[i].to,k,s+edge[i].len);
33     return sum;
34 }
35 double get_cost(int k,int fa=0,int s=0){
36     double sum=a[k]*pow(s,1.5);
37     for(int i=head[k];i!=-1;i=edge[i].nex)
38         if (edge[i].to!=fa)sum+=get_cost(edge[i].to,k,s+edge[i].len);
39     return sum;
40 }
41 int dfs(int k){
42     get_sz(k,0);
43     get_rt(k,0,sz[k]);
44     int pos=0;
45     double s=1;
46     for(int i=head[rt];i!=-1;i=edge[i].nex){
47         double ss=get_s(edge[i].to,rt,edge[i].len-1);
48         if (ss<s)pos=edge[i].to,s=ss;
49     }
50     if ((!pos)||(get_cost(rt)<=get_cost(pos)))return rt;
51     vis[rt]=1;
52     return dfs(pos);
53 }
54 int main(){
55     scanf("%d",&n);
56     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
57     memset(head,-1,sizeof(head));
58     for(int i=1;i<n;i++){
59         scanf("%d%d%d",&x,&y,&z);
60         add(x,y,z),add(y,x,z);
61         assert(z>=1);
62     }
63     x=dfs(1);
64     printf("%d %.7f\n",x,get_cost(x));
65     return 0;
66 }
View Code

 

posted @ 2021-09-30 09:59  PYWBKTDA  阅读(35)  评论(0编辑  收藏  举报