[loj2469]最小方差生成树
2018年论文题
约定:令点集$V=[1,n]$、边集$E=[1,m]$,记$m$条边依次为$e_{i}=(x_{i},y_{i},c_{i})$(其中$1\le i\le m$),将其按照$c_{i}$从小到大排序,即不妨假设有$c_{1}\le c_{2}\le...\le c_{m}$
先来考虑$T=1$的情况,即如何求最小方差生成树
题意即求$\min_{E_{T}\subseteq E,E_{T}为生成树}\frac{\sum_{x\in E_{T}}(\mu-c_{x})^{2}}{n-1}$(其中$\mu=\frac{\sum_{x\in 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_{x\in E_{T}}(\mu-c_{x})^{2}}{n-1}=\min_{\mu\in R}\frac{\sum_{x\in E_{T}}(\mu-c_{x})^{2}}{n-1}$
代入后交换顺序,即$\min_{\mu\in R}\frac{\min_{E_{T}\subseteq E,E_{T}为生成树}\sum_{x\in E_{T}}(\mu-c_{x})^{2}}{n-1}$,其中分子即以$(\mu-c_{i})^{2}$为边权求最小生成树
令$E_{\chi}$表示$\mu=\chi$时最小生成树的边集,为了使其能被唯一确定,求最小生成树时将$e_{i}$按照$(\mu-c_{i})^{2}$和$i$这两个关键字从小到大排序(假设用kruskal求最小生成树)
将问题从边的角度来考虑,显然$i\in E_{\chi}$当且仅当$\mu=\chi$时排在$e_{i}$前面的边不能使$x_{i}$和$y_{i}$连通
不妨假设$\chi \le c_{i}$,那么$e_{j}$排在$e_{i}$前面当且仅当$2\chi-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}$,那么满足$\chi\le c_{i}$且$i\in E_{\chi}$的$\chi$的范围为$\frac{c_{i}+c_{k}}{2}<\chi\le c_{i}$
(特别的,若最后仍未连通即令$c_{k}=-\infty$)
显然,使用LCT维护$i$之前的边(不包括$i$)关于编号的最大生成树,询问的也即该生成树从$x_{i}$到$y_{i}$路径上的编号最小的边,时间复杂度为$o(m\log m)$
关于$\chi>c_{i}$且$i\in 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}$即为无解
进而将两个范围求并,即得到满足$i\in 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(m\log m)$,可以通过
下面考虑$T=2$的情况,即如何对删去每一条边后的图求最小方差生成树
通过$T=1$时的做法,即可在$o(m\log m)$的时间内求出最小方差生成树即其方案
显然删除方案以外的边是不影响答案的,因此只需要考虑方案中的$n-1$条边,那么对这$n-1$条边暴力删除并再求一次最小方差生成树,即得到一个$o(nm\log 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(nm\log m)$,注意到总共只会额外产生$o(n^{2})$个位置,将这些位置预处理出来并排序,然后将初始的差分数组记录
此时,每一次即对差分数组的$o(n)$个位置修改,总复杂度也即$o(m\log m+n^{2}\log m+nm)$
时间复杂度为$o(m\log m+n^{2}\log m+nm)$,可以通过
然而,注意到答案的范围为$n^{2}C^{2}$,而在子任务8该值达到了$10^{41}$的级别,无法使用__int128存储
由此,即需要在差分的过程中使用高精度乘法求$S_{1}^{2}$(显然其他都不需要高精度),设高精度的常数为$o(P)$,时间复杂度即变为$o(m\log n+n^{2}\log m+Pnm)$,无法通过
下面,具体的来描述差分的过程——
令$N=n^{2}+m$,差分数组即是两个长度为$N$的序列,初始为分别为$\Delta S_{1}(i)$和$\Delta S_{2}(i)$(下标为$[1,N]$)
每一次查询,修改其中$o(n)$个位置的值(无后效性),并查询
$$
\min_{1\le i\le N}\left((n-1)\sum_{j=1}^{i}\Delta S_{2}(j)-(\sum_{j=1}^{i}\Delta S_{1}(i))^{2}\right)
$$
(其余部分的复杂度显然都可以做到$o(m\log 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]$分别求出$i\in [l,r]$的最小值
(其中$[l,r]$不包含修改的位置,修改的位置直接暴力$o(Pn^{2})$计算即可)
对于$[l,r]$,求出此次修改对$i\in [l,r]$的$S_{1}(i)$和$S_{2}(i)$的变化量,分别记作$\Delta s_{1}$和$\Delta s_{2}$(显然对所有位置都相同),那么$i\in [l,r]$的最小值即
$$
\min_{i=l}^{r}\left((n-1)(S_{2}(i)+\Delta s_{2})-(S_{1}(i)+\Delta s_{1})^{2}\right)
$$
并对于其中一段$[l,r]$,求出其之前的本次修改的变化量$\Delta s_{1}$和$\Delta s_{2}$
简单化简,即
$$
\min_{i=l}^{r}\left(-2\Delta s_{1}S_{1}(i)+((n-1)S_{2}(i)-S_{1}^{2}(i))\right)+\left((n-1)\Delta s_{2}-\Delta s_{1}^{2}\right)
$$
此时,问题即可以看作求经过$(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(PN\log 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+PN\log N)$,可以通过
(代码只优化到$o(m\log 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='\0'){
48 if (x.p)putchar('-');
49 for(int i=0;i<x.len;i++)
50 for(int j=0;j<9;j++){
51 num[++num[0]]=x.a[i]%10;
52 x.a[i]/=10;
53 }
54 while ((num[0])&&(!num[num[0]]))num[0]--;
55 if (!num[0])putchar('0');
56 while (num[0])putchar(num[num[0]--]+'0');
57 putchar(c);
58 }
59 };
60 namespace Calc{
61 int cmp(Num x,Num y){
62 if (x.len!=y.len){
63 if (x.len<y.len)return -1;
64 return 1;
65 }
66 for(int i=x.len-1;i>=0;i--)
67 if (x.a[i]!=y.a[i]){
68 if (x.a[i]<y.a[i])return -1;
69 return 1;
70 }
71 return 0;
72 }
73 Num min(Num x,Num y){
74 if (cmp(x,y)<0)return x;
75 return y;
76 }
77 Num add(Num x,Num y){
78 Num ans;
79 if (x.p==y.p){
80 ans.p=x.p,ans.len=max(x.len,y.len);
81 for(int i=0;i<ans.len;i++){
82 ans.a[i]+=x.a[i]+y.a[i];
83 if (ans.a[i]>=base){
84 ans.a[i]-=base;
85 ans.a[i+1]++;
86 }
87 }
88 if ((ans.len<5)&&(ans.a[ans.len]))ans.len++;
89 return ans;
90 }
91 if (cmp(x,y)<0)swap(x,y);
92 ans.p=x.p,ans.len=x.len;
93 for(int i=0;i<ans.len;i++){
94 ans.a[i]+=x.a[i]-y.a[i];
95 if (ans.a[i]<0){
96 ans.a[i]+=base;
97 ans.a[i+1]--;
98 }
99 }
100 while ((ans.len)&&(!ans.a[ans.len-1]))ans.len--;
101 return ans;
102 }
103 Num dec(Num x,Num y){
104 y.p^=1;
105 return add(x,y);
106 }
107 Num mul(Num x,Num y){
108 Num ans;
109 ans.p=(x.p^y.p),ans.len=x.len+y.len-1;
110 for(int i=0;i<x.len;i++)
111 for(int j=0;j<y.len;j++){
112 ans.a[i+j]+=x.a[i]*y.a[j];
113 ans.a[i+j+1]+=ans.a[i+j]/base;
114 ans.a[i+j]%=base;
115 }
116 if ((ans.len<5)&&(ans.a[ans.len]))ans.len++;
117 return ans;
118 }
119 };
120 namespace LCT{
121 int vis[M],st[M<<1],fa[M<<1],mn[M<<1],mx[M<<1],rev[M<<1],ch[M<<1][2];
122 int which(int k){
123 return ch[fa[k]][1]==k;
124 }
125 bool check(int k){
126 return ch[fa[k]][which(k)]==k;
127 }
128 void upd(int k){
129 rev[k]^=1;
130 swap(ch[k][0],ch[k][1]);
131 }
132 void up(int k){
133 mn[k]=min(mn[ch[k][0]],mn[ch[k][1]]);
134 mx[k]=max(mx[ch[k][0]],mx[ch[k][1]]);
135 if (k>n){
136 mn[k]=min(mn[k],k-n);
137 mx[k]=max(mx[k],k-n);
138 }
139 }
140 void down(int k){
141 if (rev[k]){
142 if (ch[k][0])upd(ch[k][0]);
143 if (ch[k][1])upd(ch[k][1]);
144 rev[k]=0;
145 }
146 }
147 void rotate(int k){
148 int f=fa[k],g=fa[f],p=which(k);
149 fa[k]=g;
150 if (check(f))ch[g][which(f)]=k;
151 fa[ch[k][p^1]]=f,ch[f][p]=ch[k][p^1];
152 fa[f]=k,ch[k][p^1]=f;
153 up(f),up(k);
154 }
155 void splay(int k){
156 for(int i=k;check(i);i=fa[i])st[++st[0]]=fa[i];
157 while (st[0])down(st[st[0]--]);
158 down(k);
159 for(int i=fa[k];check(k);i=fa[k]){
160 if (check(i)){
161 if (which(i)==which(k))rotate(i);
162 else rotate(k);
163 }
164 rotate(k);
165 }
166 }
167 void access(int k){
168 int lst=0;
169 while (k){
170 splay(k);
171 ch[k][1]=lst,up(k);
172 lst=k,k=fa[k];
173 }
174 }
175 void make_root(int k){
176 access(k);
177 splay(k);
178 upd(k);
179 }
180 int find_root(int k){
181 access(k);
182 splay(k);
183 while (ch[k][0]){
184 down(k);
185 k=ch[k][0];
186 }
187 splay(k);
188 return k;
189 }
190 void add(int x,int y){
191 make_root(x);
192 make_root(y);
193 fa[y]=x;
194 }
195 void del(int x,int y){
196 make_root(x);
197 access(y);
198 splay(x);
199 fa[y]=ch[x][1]=0,up(x);
200 }
201 int query_min(int x,int y){
202 make_root(x);
203 if (find_root(y)!=x)return 0;
204 return mn[x];
205 }
206 int query_max(int x,int y){
207 make_root(x);
208 if (find_root(y)!=x)return 0;
209 return mx[x];
210 }
211 int add_min(int id){
212 int pos=query_min(e[id].y,id+n);
213 if (pos){
214 vis[0]--,vis[pos]=0;
215 LCT::del(e[pos].y,pos+n);
216 }
217 vis[0]++,vis[id]=1;
218 LCT::add(e[id].y,id+n);
219 return pos;
220 }
221 int add_max(int id){
222 int pos=query_max(e[id].y,id+n);
223 if (pos){
224 vis[0]--,vis[pos]=0;
225 LCT::del(e[pos].y,pos+n);
226 }
227 vis[0]++,vis[id]=1;
228 LCT::add(e[id].y,id+n);
229 return pos;
230 }
231 void init(){
232 mn[0]=0x3f3f3f3f,mx[0]=0;
233 for(int i=1;i<=n+m;i++){
234 fa[i]=rev[i]=ch[i][0]=ch[i][1]=0;
235 up(i);
236 }
237 for(int i=1;i<=m;i++)add(e[i].x,i+n);
238 }
239 void clear(){
240 for(int i=1;i<=m;i++)
241 if (vis[i]){
242 LCT::del(e[i].y,i+n);
243 vis[0]--,vis[i]=0;
244 }
245 }
246 };
247 void get_LR(){
248 memset(L0,0,sizeof(L0));
249 memset(R0,0,sizeof(R0));
250 LCT::clear();
251 for(int i=1;i<=m;i++){
252 L0[i]=LCT::add_min(i);
253 if (L0[i])R0[L0[i]]=i;
254 }
255 }
256 void get_T12(){
257 LCT::clear();
258 for(int i=1;i<=m;i++){
259 if (vis0[i]){
260 for(int j=m;j;j--)
261 if (LCT::vis[j])T1[i].push_back(j);
262 }
263 LCT::add_min(i);
264 }
265 LCT::clear();
266 for(int i=m;i;i--){
267 if (vis0[i]){
268 for(int j=1;j<=m;j++)
269 if (LCT::vis[j])T2[i].push_back(j);
270 }
271 LCT::add_max(i);
272 }
273 }
274 void get_v(){
275 v0.clear();
276 for(int i=1;i<=m;i++){
277 if (!L0[i])v0.push_back(make_pair(0,i));
278 else v0.push_back(make_pair((e[L0[i]].z+e[i].z<<1)+1,i));
279 if (R0[i])v0.push_back(make_pair((e[i].z+e[R0[i]].z<<1)+1,-i));
280 }
281 }
282 void upd_LR(int k){
283 LCT::clear();
284 memcpy(L,L0,sizeof(L));
285 L[k]=k;
286 for(int i=0;i<T2[k].size();i++){
287 L[T2[k][i]]=0;
288 LCT::add_max(T2[k][i]);
289 }
290 for(int i=0;i<T1[k].size();i++){
291 int pos=LCT::add_max(T1[k][i]);
292 if (pos)L[pos]=T1[k][i];
293 }
294 memset(R,0,sizeof(R));
295 for(int i=1;i<=m;i++)
296 if (L[i])R[L[i]]=i;
297 }
298 void upd_v(int k){
299 T1[k].push_back(k),T2[k].push_back(k);
300 for(int i=0;i<T1[k].size();i++){
301 int pos=T1[k][i];
302 if (R0[pos])v[k].push_back(make_pair((e[pos].z+e[R0[pos]].z<<1)+1,pos));
303 if (R[pos]){
304 v0.push_back(make_pair((e[pos].z+e[R[pos]].z<<1)+1,0));
305 v[k].push_back(make_pair((e[pos].z+e[R[pos]].z<<1)+1,-pos));
306 }
307 }
308 for(int i=0;i<T2[k].size();i++){
309 int pos=T2[k][i];
310 if (!L0[pos])v[k].push_back(make_pair(0,-pos));
311 else v[k].push_back(make_pair((e[L0[pos]].z+e[pos].z<<1)+1,-pos));
312 if (!L[pos]){
313 v0.push_back(make_pair(0,0));
314 v[k].push_back(make_pair(0,pos));
315 }
316 else{
317 v0.push_back(make_pair((e[L[pos]].z+e[pos].z<<1)+1,0));
318 v[k].push_back(make_pair((e[L[pos]].z+e[pos].z<<1)+1,pos));
319 }
320 }
321 }
322 void unique(){
323 sort(v0.begin(),v0.end());
324 q=0;
325 for(int i=0;i<v0.size();i++){
326 if ((!i)||(v0[i].fi!=v0[i-1].fi))Pos[++q]=v0[i].fi;
327 int pos=abs(v0[i].se);
328 if (v0[i].se>0)dS1[q]=Calc::add(dS1[q],z1[pos]),dS2[q]=Calc::add(dS2[q],z2[pos]);
329 else dS1[q]=Calc::dec(dS1[q],z1[pos]),dS2[q]=Calc::dec(dS2[q],z2[pos]);
330 }
331 }
332 void calc(){
333 sort(v0.begin(),v0.end());
334 S1=S2=0,ans.len=10;
335 for(int i=0;i<v0.size();i++){
336 int pos=abs(v0[i].se);
337 if (v0[i].se>0)S1=Calc::add(S1,z1[pos]),S2=Calc::add(S2,z2[pos]);
338 else S1=Calc::dec(S1,z1[pos]),S2=Calc::dec(S2,z2[pos]);
339 if ((i==v0.size())||(v0[i].fi!=v0[i+1].fi)){
340 if (!v0[i].fi)Check=S1;
341 ans=Calc::min(ans,Calc::dec(S2,Calc::mul(S1,S1)));
342 }
343 }
344 S1=S2=0;
345 memset(vis0,0,sizeof(vis0));
346 for(int i=0;i<v0.size();i++){
347 int pos=abs(v0[i].se);
348 vis0[pos]^=1;
349 if (v0[i].se>0)S1=Calc::add(S1,z1[pos]),S2=Calc::add(S2,z2[pos]);
350 else S1=Calc::dec(S1,z1[pos]),S2=Calc::dec(S2,z2[pos]);
351 if (((i==v0.size())||(v0[i].fi!=v0[i+1].fi))&&(!Calc::cmp(ans,Calc::dec(S2,Calc::mul(S1,S1)))))break;
352 }
353 }
354 void calc(int k){
355 for(int i=0;i<v[k].size();i++){
356 int q0=lower_bound(Pos+1,Pos+q+1,v[k][i].fi)-Pos,pos=abs(v[k][i].se);
357 if (v[k][i].se>0)dS1[q0]=Calc::add(dS1[q0],z1[pos]),dS2[q0]=Calc::add(dS2[q0],z2[pos]);
358 else dS1[q0]=Calc::dec(dS1[q0],z1[pos]),dS2[q0]=Calc::dec(dS2[q0],z2[pos]);
359 }
360 if (Calc::cmp(dS1[1],Check)<0){
361 ans=-1;
362 return;
363 }
364 S1=S2=0,ans.len=10;
365 for(int i=1;i<=q;i++){
366 S1=Calc::add(S1,dS1[i]),S2=Calc::add(S2,dS2[i]);
367 ans=Calc::min(ans,Calc::dec(S2,Calc::mul(S1,S1)));
368 }
369 for(int i=0;i<v[k].size();i++){
370 int q0=lower_bound(Pos+1,Pos+q+1,v[k][i].fi)-Pos,pos=abs(v[k][i].se);
371 if (v[k][i].se<0)dS1[q0]=Calc::add(dS1[q0],z1[pos]),dS2[q0]=Calc::add(dS2[q0],z2[pos]);
372 else dS1[q0]=Calc::dec(dS1[q0],z1[pos]),dS2[q0]=Calc::dec(dS2[q0],z2[pos]);
373 }
374 }
375 int main(){
376 n=IO::read(),m=IO::read(),T=IO::read();
377 for(int i=1;i<=m;i++){
378 e[i].x=IO::read(),e[i].y=IO::read(),e[i].z=IO::read();
379 e[i].id=i;
380 }
381 sort(e+1,e+m+1);
382 LCT::init();
383 for(int i=1;i<=m;i++){
384 z1[i]=e[i].z;
385 z2[i]=Calc::mul(n-1,Calc::mul(z1[i],z1[i]));
386 }
387 get_LR();
388 if (LCT::vis[0]!=n-1){
389 if (T==1)IO::write(-1,'\n');
390 else{
391 for(int i=1;i<=m;i++)IO::write(-1,'\n');
392 }
393 return 0;
394 }
395 get_v(),calc();
396 if (T==1){
397 IO::write(ans,'\n');
398 return 0;
399 }
400 for(int i=1;i<=m;i++)
401 if (!vis0[i])Ans[e[i].id]=ans;
402 get_T12();
403 for(int i=1;i<=m;i++)
404 if (vis0[i])upd_LR(i),upd_v(i);
405 unique();
406 for(int i=1;i<=m;i++)
407 if (vis0[i]){
408 calc(i);
409 Ans[e[i].id]=ans;
410 }
411 for(int i=1;i<=m;i++)IO::write(Ans[i],'\n');
412 return 0;
413 }
[loj2469]最小方差生成树的更多相关文章
- 算法提高 最小方差生成树(Kruskal)_模板
算法提高 最小方差生成树 时间限制:1.0s 内存限制:256.0MB 问题描述 给定带权无向图,求出一颗方差最小的生成树. 输入格式 输入多组测试数据.第一行为N,M,依次是 ...
- 算法笔记_164:算法提高 最小方差生成树(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 给定带权无向图,求出一颗方差最小的生成树. 输入格式 输入多组测试数据.第一行为N,M,依次是点数和边数.接下来M行,每行三个整数U,V, ...
- Java实现 蓝桥杯 算法提高最小方差生成树
1 问题描述 给定带权无向图,求出一颗方差最小的生成树. 输入格式 输入多组测试数据.第一行为N,M,依次是点数和边数.接下来M行,每行三个整数U,V,W,代表连接U,V的边,和权值W.保证图连通.n ...
- [BZOJ3080]Minimum Variance Spanning Tree/[BZOJ3754]Tree之最小方差树
[BZOJ3080]Minimum Variance Spanning Tree/[BZOJ3754]Tree之最小方差树 题目大意: 给定一个\(n(n\le50)\)个点,\(m(m\le1000 ...
- bzoj 3754: Tree之最小方差树 模拟退火+随机三分
题目大意: 求最小方差生成树.N<=100,M<=2000,Ci<=100 题解: 首先我们知道这么一个东西: 一些数和另一个数的差的平方之和的最小值在这个数是这些数的平均值时取得 ...
- [BZOJ3754]Tree之最小方差树
3754: Tree之最小方差树 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 402 Solved: 152[Submit][Status][Di ...
- 【bzoj3754】Tree之最小方差树 最小生成树
题目描述 给出一张无向图,求它的一棵生成树,使得选出的所有边的方差最小.输出这个最小方差. 输入 第一行两个正整数N,M 接下来M行,每行三个正整数Ui,Vi,Ci N<=100,M<=2 ...
- bzoj2395[Balkan 2011]Timeismoney最小乘积生成树
所谓最小乘积生成树,即对于一个无向连通图的每一条边均有两个权值xi,yi,在图中找一颗生成树,使得Σxi*Σyi取最小值. 直接处理问题较为棘手,但每条边的权值可以描述为一个二元组(xi,yi),这也 ...
- HDU5697 刷题计划 dp+最小乘积生成树
分析:就是不断递归寻找靠近边界的最优解 学习博客(必须先看这个): 1:http://www.cnblogs.com/autsky-jadek/p/3959446.html 2:http://blog ...
随机推荐
- 前端VUE基于gitlab的CI_CD
目录 CI 1.Gitlab的CI 1.1 GitLab-Runner 1.2 .gitlab-ci.yml 1.3 配置.gitlab-ci.yml 1.3.1 Pipeline概念 1.3.2 S ...
- docker - compose 部署 Nginx
主要介绍 docker 中 Nginx 的部署及项目目录挂载券的方法.docker 中部署一个服务,有三种方法,分别是 docker run.Dockerfile.docker-compose . 下 ...
- 从零入门 Serverless | 架构的演进
作者 | 许晓斌 阿里云高级技术专家 本文整理自<Serverless 技术公开课>,关注"Serverless"公众号,回复 入门 ,即可获取 Serverless ...
- 从零入门 Serverless | 一文搞懂函数计算及其工作原理
作者 | 孔德慧(夏莞) 阿里云函数计算开发工程师 什么是函数计算 大家都了解,Serverless 并不是没有服务器,而是开发者不再需要关心服务器.下图是一个应用从开发到上线的对比图: 在传统 Se ...
- Windows 10下CUDA及cuDNN的安装 —— Pytorch
Windows 10下CUDA及cuDNN的安装 CUDA简介与下载地址 CUDA(ComputeUnified Device Architecture),是显卡厂商NVIDIA推出的运算平台. CU ...
- C++手动加载CLR运行托管程序(CLR Hosting)
转载自:http://www.linuxidc.com/Linux/2012-10/72293.htm 机制介绍 有些时候主程序是通过C/C++实现的,但是我们希望通过托管代码来扩展非托管程序,从而也 ...
- JavaCPP快速入门(官方demo增强版)
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- 如果你还不知道Apache Zookeeper?你凭什么拿大厂Offer!!
很多同学或多或少都用到了Zookeeper,并知道它能实现两个功能 配置中心,实现表分片规则的统一配置管理 注册中心,实现sharding-proxy节点的服务地址注册 那么Zookeeper到底是什 ...
- VMware虚拟机安装Linux
我们都知道,Linux的学习如果依靠大量的物理真机,是不切实际的,会非常的麻烦. 今天来和分享一下VMware虚拟机安装Linux操作系统的方法 (centos 7) 1. 我们要先把VMware虚 ...
- 改善深层神经网络-week1编程题(Initializaion)
Initialization 如何选择初始化方式,不同的初始化会导致不同的结果 好的初始化方式: 加速梯度下降的收敛(Speed up the convergence of gradient desc ...