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

题目链接:hdu 5398 GCD Tree

题意:

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

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

题解:

由于题意要让你输出所有的1e5内所有的n,所以只能动态维护最大生成树。(LCT可以做到)

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

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

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

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

然后对于这题,可以先将全部的点连向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

 

posted @ 2017-10-22 10:45  bin_gege  阅读(511)  评论(0编辑  收藏  举报