• 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
    ",ans[n]));
    88     return 0;
    89 }
    View Code
  • 相关阅读:
    C++使用thread类多线程编程
    机器学习: Viola-Jones 人脸检测算法解析(二)
    微服务:ICE 入门之 编译环境搭建
    OpenMP中的同步和互斥
    OpenMP编程的任务调度控制
    机器学习: Viola-Jones 人脸检测算法解析(一)
    并行编程OpenMP基础及简单示例
    漫话中国古代史 —— 大唐
    漫话中国古代史 —— 大唐
    也咬文嚼字
  • 原文地址:https://www.cnblogs.com/bin-gege/p/7708013.html
Copyright © 2020-2023  润新知