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
相關文章
相關標籤/搜索