【LCT维护最大生成树】[HDU5389]GCD Tree

题目
分析:由于wt(u,v)=gcd(u,v),所以我们枚举gcd,而且只尝试连接gcd和它的倍数,也就是我们尝试连接(i,j),仅当j是i的倍数,至于于为什么,我也不知道。
用LCT维护最大生成树,每次连接一条边时,必定形成一个环,删除这个环中最小边即可。

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
#define MAXN 100000
#define INF 0x7fffffff
int ans[MAXN+10],T,n;
vector<int>fac[MAXN];
void Read(int &x){
    char c;
    while(c=getchar(),c!=EOF)
        if(c>='0'&&c<='9'){
            x=c-'0';
            while(c=getchar(),c>='0'&&c<='9')
                x=x*10+c-'0';
            ungetc(c,stdin);
            return;
        }
    exit(0);
}
struct node{
    int val,lgcd;
    bool pre,tag;
    node *ch[2],*fa;
}splay_tree[MAXN+10];
inline void push_down(node *p){
    if(p->tag){
        p->tag=0;
        if(p->ch[0])
            p->ch[0]->tag^=1;
        if(p->ch[1])
            p->ch[1]->tag^=1;
        swap(p->ch[0],p->ch[1]);
    }
}
inline int Get_lgcd(node *p){
    return p?p->lgcd:INF;
}
inline void update(node *p){
    p->lgcd=min(min(Get_lgcd(p->ch[0]),Get_lgcd(p->ch[1])),p->val);
}
void push_up(node *p){
    if(p->pre)
        push_up(p->fa);
    push_down(p);
}
void Rotate(node *x,int d){
    node *y=x->fa;
    if(y->pre)
        y->fa->ch[y==y->fa->ch[1]]=x;
    x->fa=y->fa;
    if(x->ch[d])
        x->ch[d]->fa=y;
    y->ch[!d]=x->ch[d];
    x->ch[d]=y;
    y->fa=x;
    swap(x->pre,y->pre);
    update(y);
}
void splay(node *x){
    node *y,*z;
    push_up(x);
    while(x->pre){
        y=x->fa;
        z=y->fa;
        if(!y->pre){
            if(x==y->ch[0])
                Rotate(x,1);
            else
                Rotate(x,0);
        }
        else if(y==z->ch[0])
            if(x==y->ch[0]){
                Rotate(y,1);
                Rotate(x,1);
            }
            else{
                Rotate(x,0);
                Rotate(x,1);
            }
        else
            if(x==y->ch[1]){
                Rotate(y,0);
                Rotate(x,0);
            }
            else{
                Rotate(x,1);
                Rotate(x,0);
            }
    }
    update(x);
}
void access(node *x){
    node *y=0,*z=x;
    while(x){
        splay(x);
        if(x->ch[1])
            x->ch[1]->pre=0;
        x->ch[1]=y;
        if(y)
            y->pre=1;
        y=x;
        x=x->fa;
    }
    splay(z);
}
inline void link(node *x,node *y){
    access(x);
    access(y);
    y->pre=y->tag=1;
    x->ch[1]=y;
    y->fa=x;
    update(x);
}
void prepare(){
    int i,j,d,nans=0,d2;
    node *x,*y,*z;
    vector<int>::iterator k;
    splay_tree[1].val=splay_tree[1].lgcd=1;
    for(i=2;i<=MAXN;i++){
        splay_tree[i].val=splay_tree[i].lgcd=i;
        link(splay_tree+i,splay_tree+1);
        nans++;
        for(j=i+i;j<=MAXN;j+=i)
            fac[j].push_back(i);
        for(k=fac[i].begin();k!=fac[i].end();k++){
            d=*k;
            x=splay_tree+i;
            y=splay_tree+d;
            access(x);
            x->tag=1;
            access(y);
            d2=y->lgcd;
            if(d2<d){
                nans+=d-d2;
                z=splay_tree+d2;
                access(z);
                splay(z);
                push_down(z);
                if(z->ch[0]){
                    z->ch[0]->fa=0;
                    z->ch[0]->pre=0;
                    z->ch[0]=0;
                }
                else{
                    z->ch[1]->fa=0;
                    z->ch[1]->pre=0;
                    z->ch[1]=0;
                }
                update(splay_tree+d2);
                link(x,y);
            }
        }
        ans[i]=nans;
    }
}
int main()
{
    prepare();
    while(1){
        Read(n);
        printf("%d\n",ans[n]);
    }
}

转载于:https://www.cnblogs.com/outerform/p/5921904.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值