hdu 5398 GCD Tree(LCT动态维护最大生成树)

题目连接:hdu 5398 GCD Treephp

题意:c++

给你一个n,让你输出一个最大生成树的价值。ide

有n个点,任意两点有条边,边权为gcd(u,v)。spa

题解:code

因为题意要让你输出全部的1e5内全部的n,因此只能动态维护最大生成树。(LCT能够作到)blog

显然可能有用的边只能是x向x的因子连的边。get

LCT如何来维护最大生成树?一个最简单的办法就是将边变成点,而后用点来记录权值。it

而后每次加入一条边(u,v)的时候,LCT查询当前树中的(u,v)链上的最小值val,若是val比加入的边的权值小,event

那么就把这条边删掉,而后加入(u,v)。class

而后对于这题,能够先将所有的点连向1,而后再来加边,每加入一个点,记录一下答案就好了。

 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=a;i<=b;i++)
 3 #define mst(a,b) memset(a,b,sizeof(a))
 4 using namespace std;
 5 typedef pair<int,int>P;
 6 namespace LCT
 7 {
 8     const int N=2e5+7;
 9     int f[N],son[N][2],tmp[N],lazy[N];bool rev[N];
10     P sum[N],val[N],eg[N];
11     bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}
12     void rev1(int x){if(!x)return;swap(son[x][0],son[x][1]);rev[x]^=1;}
13     void add(int x,P c){if(!x)return;val[x]=sum[x]=c;}
14     void pb(int x){if(rev[x])rev1(son[x][0]),rev1(son[x][1]),rev[x]=0;}
15     void up(int x){
16         sum[x]=val[x];
17         if(son[x][0])
18         {
19             if(sum[son[x][0]].first<sum[x].first)sum[x]=sum[son[x][0]];
20         }
21         if(son[x][1])
22         {
23             if(sum[son[x][1]].first<sum[x].first)sum[x]=sum[son[x][1]];
24         }
25     }
26     void rotate(int x){
27         int y=f[x],w=son[y][1]==x;
28         son[y][w]=son[x][w^1];
29         if(son[x][w^1])f[son[x][w^1]]=y;
30         if(f[y]){
31             int z=f[y];
32             if(son[z][0]==y)son[z][0]=x;else if(son[z][1]==y)son[z][1]=x;
33         }
34         f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);
35     }
36     void splay(int x){
37         int s=1,i=x,y;tmp[1]=i;
38         while(!isroot(i))tmp[++s]=i=f[i];
39         while(s)pb(tmp[s--]);
40         while(!isroot(x)){
41             y=f[x];
42             if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
43             rotate(x);
44         }
45         up(x);
46     }
47     void access(int x){for(int y=0;x;y=x,x=f[x])splay(x),son[x][1]=y,up(x);}
48     int root(int x){access(x);splay(x);while(son[x][0])x=son[x][0];return x;}
49     void makeroot(int x){access(x);splay(x);rev1(x);}
50     void link(int x,int y){makeroot(x);f[x]=y;access(x);}
51     void cutf(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;up(x);}
52     void cut(int x,int y){makeroot(x);cutf(y);}
53     P ask(int x,int y){makeroot(x);access(y);splay(y);return sum[y];}
54 }
55 using namespace LCT;
56 vector<int>g[N];
57 long long ans[N];
58 
59 void init()
60 {
61     F(i,2,100000)
62         for(int j=i+i;j<=100000;j+=i)
63             g[j].push_back(i);
64     F(i,1,100000)sum[i]=val[i]=P(N,N);
65     F(i,2,100000)
66     {
67         ans[i]=ans[i-1];
68         int nd=100000+i;
69         link(nd,1);add(nd,P(1,nd));link(i,nd);
70         eg[nd]=P(1,i),ans[i]++;
71         for(auto &it:g[i])
72         {
73             P now=ask(i,it);
74             if(it<=now.first)continue;
75             cut(eg[now.second].first,now.second);
76             cut(now.second,eg[now.second].second);
77             ans[i]+=it-now.first;
78             link(now.second,i),add(now.second,P(it,now.second));
79             link(it,now.second),eg[now.second]=P(i,it);
80         }
81     }
82 }
83 
84 int main()
85 {
86     init();
87     for(int n;~scanf("%d",&n);printf("%lld\n",ans[n]));
88     return 0;
89 }
View Code
相关文章
相关标签/搜索