转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud
GCD Tree
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 84 Accepted Submission(s): 38
Problem Description
Teacher Mai has a graph with n vertices numbered from 1 to n. For every edge(u,v), the weight is gcd(u,v). (gcd(u,v) means the greatest common divisor of number u and v).
You need to find a subset of the edges that forms a tree that includes every vertex, where the total weight of all the edges in the tree is maximized. Print the total weight of these edges.
You need to find a subset of the edges that forms a tree that includes every vertex, where the total weight of all the edges in the tree is maximized. Print the total weight of these edges.
Input
There are multiple test cases(about 105).
For each test case, there is only one line contains one number n(1≤n≤105).
For each test case, there is only one line contains one number n(1≤n≤105).
Output
For each test case, print the answer.
Sample Input
1
2
3
4
5
Sample Output
0
1
2
4
5
LCT维护最大生成树,从小到大不断加入数的时候,先和它最大的约数连边,这样就已经变成一棵树了,然后从大到小依次查询其他因子,每次查找到这个数的路径上的最小值,然后砍断这条边,把i和这次查询的因子相连,因为砍掉的边的权值一定不会超过新加的边,所以每次都在增大,这样能够保证最优
队友随手过了这题。23333333
我的写法是把边权搞成一个点,其实不这样也行,找出最小的点,然后看一下在路径上和这个点相邻的点。
1 /** 2 * code generated by JHelper 3 * More info: https://github.com/AlexeyDmitriev/JHelper 4 * @author xyiyy @https://github.com/xyiyy 5 */ 6 7 #include <iostream> 8 #include <fstream> 9 10 //##################### 11 //Author:fraud 12 //Blog: http://www.cnblogs.com/fraud/ 13 //##################### 14 //#pragma comment(linker, "/STACK:102400000,102400000") 15 #include <iostream> 16 #include <sstream> 17 #include <ios> 18 #include <iomanip> 19 #include <functional> 20 #include <algorithm> 21 #include <vector> 22 #include <string> 23 #include <list> 24 #include <queue> 25 #include <deque> 26 #include <stack> 27 #include <set> 28 #include <map> 29 #include <cstdio> 30 #include <cstdlib> 31 #include <cmath> 32 #include <cstring> 33 #include <climits> 34 #include <cctype> 35 36 using namespace std; 37 #define XINF INT_MAX 38 #define INF 0x3FFFFFFF 39 #define mp(X, Y) make_pair(X,Y) 40 #define pb(X) push_back(X) 41 #define rep(X, N) for(int X=0;X<N;X++) 42 #define rep2(X, L, R) for(int X=L;X<=R;X++) 43 #define dep(X, R, L) for(int X=R;X>=L;X--) 44 #define clr(A, X) memset(A,X,sizeof(A)) 45 #define IT iterator 46 #define ALL(X) (X).begin(),(X).end() 47 #define PQ std::priority_queue 48 typedef long long ll; 49 typedef unsigned long long ull; 50 typedef pair<int, int> PII; 51 typedef vector<PII> VII; 52 typedef vector<int> VI; 53 54 const int MAXN = 100010; 55 int pre[MAXN<<1], ch[MAXN<<1][2], rev[MAXN<<1]; 56 int key[MAXN<<1]; 57 int lx[MAXN<<1],rx[MAXN<<1]; 58 int mx[MAXN<<1]; 59 60 void push_down(int r) { 61 if(!r)return; 62 if (rev[r]) { 63 rev[ch[r][0]] ^= 1; 64 rev[ch[r][1]] ^= 1; 65 swap(ch[r][0], ch[r][1]); 66 rev[r] ^= 1; 67 } 68 } 69 70 void push_up(int x) { 71 int l = ch[x][0],r = ch[x][1]; 72 mx[x] = x; 73 if(key[mx[l]]<key[mx[x]])mx[x] = mx[l]; 74 if(key[mx[r]]<key[mx[x]])mx[x] = mx[r]; 75 } 76 77 void rotate(int x, int d) { 78 const int y = pre[x]; 79 ch[y][!d] = ch[x][d]; 80 if (ch[x][d])pre[ch[x][d]] = y; 81 pre[x] = pre[y]; 82 if (ch[pre[y]][0] == y)ch[pre[x]][0] = x; 83 else if (ch[pre[y]][1] == y)ch[pre[x]][1] = x; 84 pre[y] = x; 85 ch[x][d] = y; 86 push_up(y); 87 } 88 89 bool _splay_parent(int x,int &y){ 90 return (y = pre[x])!=0 && (ch[y][0] == x || ch[y][1] == x); 91 } 92 93 void splay(int x,int goal) { 94 push_down(x); 95 for (int y,z;_splay_parent(x,y);) { 96 //cout<<x<<" "<<y<<endl; 97 if(_splay_parent(y,z)){ 98 push_down(z);push_down(y);push_down(x); 99 int d = y == ch[z][0]; 100 if(x == ch[y][d])rotate(x,d^1),rotate(x,d); 101 else rotate(y,d),rotate(x,d); 102 }else { 103 push_down(y),push_down(x); 104 rotate(x, x == ch[y][0]);break; 105 } 106 } 107 push_up(x); 108 } 109 110 int access(int u) { 111 int v = 0; 112 for (; u; u = pre[u]) { 113 splay(u,0); 114 ch[u][1] = v; 115 push_up(v = u); 116 } 117 return v; 118 } 119 120 void makeroot(int x) { 121 rev[access(x)] ^= 1; 122 splay(x,0); 123 } 124 125 void link(int x, int y) { 126 makeroot(x); 127 pre[x] = y; 128 } 129 130 void cut(int x, int y) { 131 makeroot(x); 132 access(y); 133 splay(y,0); 134 pre[ch[y][0]] = 0; 135 ch[y][0] = 0; 136 push_up(y); 137 } 138 139 void Init(int n) { 140 for (int i = 0; i < n; i++) { 141 pre[i] = ch[i][0] = ch[i][1] = 0; 142 key[i] = INF; 143 mx[i] = 0; 144 } 145 } 146 void debug(int x){ 147 148 } 149 int query(int x, int y) { 150 makeroot(x); 151 access(y); 152 splay(y,0); 153 return mx[y]; 154 } 155 156 157 vector<int> vec[MAXN]; 158 int ans[MAXN]; 159 160 class hdu5398 { 161 public: 162 void solve(std::istream &in, std::ostream &out) { 163 rep2(i, 2, MAXN-1) { 164 vec[i].pb(1); 165 for (int j = 2; j * j <= i; j++) { 166 if (i % j == 0) { 167 vec[i].pb(j); 168 if (i / j != j)vec[i].pb(i / j); 169 } 170 } 171 sort(vec[i].begin(),vec[i].end()); 172 } 173 Init(MAXN<<1); 174 ans[1] = 0; 175 rep2(i, 2, MAXN-5) { 176 int sz = vec[i].size(); 177 int y = vec[i][sz - 1]; 178 ans[i] = ans[i - 1]; 179 link(i, MAXN + i); 180 rx[MAXN + i] = i; 181 link(y, MAXN + i); 182 lx[MAXN + i] = y; 183 key[MAXN + i] = y; 184 ans[i] += y; 185 dep(j, sz - 2, 0) { 186 y = vec[i][j]; 187 int x = query(y, i); 188 cut(x,lx[x]); 189 cut(x,rx[x]); 190 link(y, x); 191 link(i, x); 192 ans[i] -= key[x]; 193 key[x] = y; 194 lx[x] = y; 195 rx[x] = i; 196 ans[i] += y; 197 } 198 } 199 int n; 200 while(in>>n){ 201 out<<ans[n]<<endl; 202 } 203 204 } 205 }; 206 207 int main() { 208 std::ios::sync_with_stdio(false); 209 std::cin.tie(0); 210 hdu5398 solver; 211 std::istream &in(std::cin); 212 std::ostream &out(std::cout); 213 solver.solve(in, out); 214 return 0; 215 }