2018年论文题
约定:令点集$V=[1,n]$、边集$E=[1,m]$,记$m$条边依次为$e_{i}=(x_{i},y_{i},c_{i})$(其中$1le ile m$),将其按照$c_{i}$从小到大排序,即不妨假设有$c_{1}le c_{2}le...le c_{m}$
先来考虑$T=1$的情况,即如何求最小方差生成树
题意即求$min_{E_{T}subseteq E,E_{T}为生成树}frac{sum_{xin E_{T}}(mu-c_{x})^{2}}{n-1}$(其中$mu=frac{sum_{xin E_{T}}c_{x}}{n-1}$)
考虑函数$f(x)=frac{sum_{i=1}^{n-1}(x-a_{i})^{2}}{n-1}$,根据二次函数的性质其最小值恰在$x=frac{sum_{i=1}^{n-1}a_{i}}{n-1}$处取到
换言之,有$frac{sum_{xin E_{T}}(mu-c_{x})^{2}}{n-1}=min_{muin R}frac{sum_{xin E_{T}}(mu-c_{x})^{2}}{n-1}$
代入后交换顺序,即$min_{muin R}frac{min_{E_{T}subseteq E,E_{T}为生成树}sum_{xin E_{T}}(mu-c_{x})^{2}}{n-1}$,其中分子即以$(mu-c_{i})^{2}$为边权求最小生成树
令$E_{chi}$表示$mu=chi$时最小生成树的边集,为了使其能被唯一确定,求最小生成树时将$e_{i}$按照$(mu-c_{i})^{2}$和$i$这两个关键字从小到大排序(假设用kruskal求最小生成树)
将问题从边的角度来考虑,显然$iin E_{chi}$当且仅当$mu=chi$时排在$e_{i}$前面的边不能使$x_{i}$和$y_{i}$连通
不妨假设$chi le c_{i}$,那么$e_{j}$排在$e_{i}$前面当且仅当$2chi-c_{i}le c_{j}<c_{i}$或$c_{j}=c_{i}$且$j<i$
显然$chi$的范围具有单调性,即只需要不断加入$e_{i-1},e_{i-2},...$直至$x_{i}$和$y_{i}$连通,设最后一条边加入的是$e_{k}$,那么满足$chile c_{i}$且$iin E_{chi}$的$chi$的范围为$frac{c_{i}+c_{k}}{2}<chile c_{i}$
(特别的,若最后仍未连通即令$c_{k}=-infty$)
显然,使用LCT维护$i$之前的边(不包括$i$)关于编号的最大生成树,询问的也即该生成树从$x_{i}$到$y_{i}$路径上的编号最小的边,时间复杂度为$o(mlog m)$
关于$chi>c_{i}$且$iin E_{chi}$的范围,可以类似地求出,但会多一个2的常数,实际上可以避免
记$l_{i}$为最大的$k$满足$e[k,i)$能使$x_{i}$和$y_{i}$连通,$r_{i}$为最小的$k$满足$e(i,k]$能使$x_{i}$和$y_{i}$连通
结论:若$L_{i}$存在,则$R_{L_{i}}=i$;若$R_{i}$存在,则$R_{L_{i}}=i$
记$k=L_{i}$,则$e[k,i)$能使$x_{i}$和$y_{i}$连通,那么$e(k,i]$即能使$x_{k}$和$y_{k}$连通,也即$R_{k}le i$
另一方面,如果$e(k,i)$就能使$x_{k}$和$y_{k}$连通,那么$e[k,i)$与$e(k,i)$的连通性应该相同(因为$(x_{k},y_{k})$不影响连通性),也即$l_{i}$可以为$k+1$,与$L_{i}$的最大性矛盾,因此$R_{k}ge i$
综上,即有$R_{k}=i$,类似地也可以得到后者
由此即可线性求出$R_{i}$($L_{i}$之前已求出),根据后半部分,未被覆盖的$R_{i}$即为无解
进而将两个范围求并,即得到满足$iin E_{chi}$的$chi$的范围为$(frac{c_{L_{i}}+c_{i}}{2},frac{c_{i}+c_{R_{i}}}{2}]$
此时,$E_{chi}$即对应范围包含$chi$的$i$所组成的集合(注意这个范围是充分必要的),那么只需要通过离散和差分对每一个位置维护$S_{1}=sum c_{i}$和$S_{2}=sum c^{2}_{i}$的和即可(方差即$frac{(n-1)S_{2}-S_{1}^{2}}{(n-1)^{2}}$)
另外,需要考虑实数的位置如何处理,可以将权值乘2并用两整数中间的部分代替该段实数
时间复杂度为$o(mlog m)$,可以通过
下面考虑$T=2$的情况,即如何对删去每一条边后的图求最小方差生成树
通过$T=1$时的做法,即可在$o(mlog m)$的时间内求出最小方差生成树即其方案
显然删除方案以外的边是不影响答案的,因此只需要考虑方案中的$n-1$条边,那么对这$n-1$条边暴力删除并再求一次最小方差生成树,即得到一个$o(nmlog m)$的做法,但无法通过
假设删除的边是$e_{del}$,那么$L_{i}$发生变化的边必然都在$e(del,m]$这些边关于编号的最小生成树上,因为如果$e_{i}$不在最小生成树上,即等价于$e(del,i)$能使$x_{i}$和$y_{i}$连通,显然删去$e_{del}$没有意义
显然这样的边只有$o(n)$条,但求最大生成树仍要从前往后依次加边,复杂度并没有优化
记$T_{1}$为$e[1,del)$的关于编号的最大生成树,$T_{2}$为$e(del,m]$的关于编号的最小生成树
初始令$T=T_{2}$,并将$T_{1}$中的边的按编号从大到小依次加入$T$,并继续维护$T$为最小生成树
结论:假设在加入$e_{i}$时删除了$e_{j}$,则有$L_{j}=i$
显然$x_{j}$到$y_{j}$路径上所有边编号都在$[i,j)$中,因此也即$L_{j}ge i$
同时如果$L_{j}>i$,那么不难得到$x_{i}$和$y_{i}$可以通过$e(i,del)$连通,与$e_{i}$在$T_{1}$上矛盾
通俗的来说,求$e[1,i)$的最大生成树上在$e_{del}$之前的边一定在$e[1,del)$的最大生成树上,并且$e_{del}$之后的边一定不会作为$l_{i}$,因此只关心于这类边的连通性
另外,对于$T_{1}$中最终仍没有被删除的边$e_{i}$,则$L_{i}$无解
此时,重新计算$L_{i}$和$R_{i}$的时间复杂度即降为$o(n^{2}log m)$
下面,给出一些关于实现上的细节:
1.关于LCT的清空,可以维护一个当前的边集(用标记数组即可),那么清空时遍历所有边并用删掉即可,由于删除的复杂度与加入时相同,因此相当于仅为$o(m)$,总复杂度也即$o(nm)$
2.关于$T_{1}$和$T_{2}$需要在初始预处理,在求最小/最大生成树过程中,当访问到的边是在方案中时,就将当前LCT中维护的边集$o(m)$找出即可,总复杂度也为$o(nm)$
3.关于离散和差分,重新暴力排序+二分复杂度又会退化为$o(nmlog m)$,注意到总共只会额外产生$o(n^{2})$个位置,将这些位置预处理出来并排序,然后将初始的差分数组记录
此时,每一次即对差分数组的$o(n)$个位置修改,总复杂度也即$o(mlog m+n^{2}log m+nm)$
时间复杂度为$o(mlog m+n^{2}log m+nm)$,可以通过
然而,注意到答案的范围为$n^{2}C^{2}$,而在子任务8该值达到了$10^{41}$的级别,无法使用__int128存储
由此,即需要在差分的过程中使用高精度乘法求$S_{1}^{2}$(显然其他都不需要高精度),设高精度的常数为$o(P)$,时间复杂度即变为$o(mlog n+n^{2}log m+Pnm)$,无法通过
下面,具体的来描述差分的过程——
令$N=n^{2}+m$,差分数组即是两个长度为$N$的序列,初始为分别为$Delta S_{1}(i)$和$Delta S_{2}(i)$(下标为$[1,N]$)
每一次查询,修改其中$o(n)$个位置的值(无后效性),并查询
$$
min_{1le ile N}left((n-1)sum_{j=1}^{i}Delta S_{2}(j)-(sum_{j=1}^{i}Delta S_{1}(i))^{2}
ight)
$$
(其余部分的复杂度显然都可以做到$o(mlog m+n^{2}log m+nm+Pn^{2})$,其中$o(Pn^{2})$为计算修改的值)
预处理出前缀和$S_{1}(i)=sum_{j=1}^{i}Delta S_{1}(j),S_{2}(i)=sum_{j=1}^{i}Delta S_{2}(j)$(对于初始状态),每一次修改的$o(n)$个位置即将原序列划分为$o(n)$段,并对每一段$[l,r]$分别求出$iin [l,r]$的最小值
(其中$[l,r]$不包含修改的位置,修改的位置直接暴力$o(Pn^{2})$计算即可)
对于$[l,r]$,求出此次修改对$iin [l,r]$的$S_{1}(i)$和$S_{2}(i)$的变化量,分别记作$Delta s_{1}$和$Delta s_{2}$(显然对所有位置都相同),那么$iin [l,r]$的最小值即
$$
min_{i=l}^{r}left((n-1)(S_{2}(i)+Delta s_{2})-(S_{1}(i)+Delta s_{1})^{2}
ight)
$$
并对于其中一段$[l,r]$,求出其之前的本次修改的变化量$Delta s_{1}$和$Delta s_{2}$
简单化简,即
$$
min_{i=l}^{r}left(-2Delta s_{1}S_{1}(i)+((n-1)S_{2}(i)-S_{1}^{2}(i))
ight)+left((n-1)Delta s_{2}-Delta s_{1}^{2}
ight)
$$
此时,问题即可以看作求经过$(2S_{1}(i),(n-1)S_{2}(i)-S_{1}^{2}(i))$且斜率为$-Delta s_{1}$的直线的最小截距
求出$[l,r]$中的点所构成的下凸壳,二分找到其中第一个斜率大于等于$-Delta s_{1}$的线段的左端点即为最小值
可以使用线段树来维护,预处理时先将所有点按照$x$坐标排序,并依次加入线段树上区间包含其的$o(log N)$个凸包中,那么预处理的时间复杂度即为$o(PNlog N)$
查询时将$[l,r]$划分为$o(log N)$个区间,再在每一个区间对应的线段树凸包上二分,将所有最小值取$min$即可,那么查询的时间复杂度为$o(Pn^{2}log^{2}N)$
进一步的,可以将线段树每一个区间对应的凸包上的询问离线并排序,再利用单调性做到线性即可
关于排序,再将所有$-Delta s_{1}$排序再依次加入,注意到外部仅有$o(n^{2})$个,因此查询复杂度降为$o(Pn^{2}log N)$
时间复杂度为$o(nm+PNlog N)$,可以通过
(代码只优化到$o(mlog m+n^{2}log m+Pnm)$,但已经可以通过)

1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 305 4 #define M 100005 5 #define base 1000000000 6 #define ll long long 7 #define pli pair<ll,int> 8 #define fi first 9 #define se second 10 struct Data{ 11 int x,y,id; 12 ll z; 13 bool operator < (const Data &k)const{ 14 return z<k.z; 15 } 16 }e[M]; 17 struct Num{ 18 int p,len; 19 ll a[5]; 20 Num(ll k=0){ 21 p=(k<0),len=0; 22 memset(a,0,sizeof(a)); 23 k=abs(k); 24 while (k){ 25 a[len++]=k%base; 26 k/=base; 27 } 28 } 29 }Check,S1,S2,ans,z1[M],z2[M],dS1[M<<1],dS2[M<<1],Ans[M]; 30 vector<int>T1[M],T2[M]; 31 vector<pli>v0,v[M]; 32 int n,m,T,q,L0[M],R0[M],L[M],R[M],vis0[M]; 33 ll Pos[M<<1]; 34 namespace IO{ 35 int num[100]; 36 ll x; 37 char c; 38 ll read(){ 39 x=0,c=getchar(); 40 while ((c<'0')||(c>'9'))c=getchar(); 41 while ((c>='0')&&(c<='9')){ 42 x=x*10+c-'0'; 43 c=getchar(); 44 } 45 return x; 46 } 47 void write(Num x,char c='