hdu5398(lct维护最大生成树)

来源:互联网 发布:有win本 mac 编辑:程序博客网 时间:2024/04/23 16:57

lct维护最大生成树,维护最小生成树,参考别人的代码理解的,但是不会证明,不明白为什么要这样做就可以得到最大生成树。

至于为什么只选择一个点是另一个点的整倍数的边,我的理解是:把每条边的权值取相反数,那样求最大生成树,就转化为求最小生成树;假设现在一共有m个点,边的最小权值是-n,很明显n<m,在求最小生成树中,根据kruskal算法来说,先选择一条权值最小的边,-n,此时,我们选(n,2n)这两个点构成的边,下面,如果3n<=m,4n<=m……的话,就将(n,3n),(n,4n),选进来,一直到n的某个倍数>m,那么此时便不存在权值为-n的安全边,接下来选权值为-(n-1)的边,同上,不过要注意选(n-1,n的倍数)的边是,要选择安全边,按照权值依次选择下去,最终选择到权值为-1的边,那么此时便可以构成最小生成时,在将边的权值取反,恢复到正值,此时便可以得到最大生成树,所以在集合{一个点是另一个点的整数倍的边}中可以构成一个最大生成树。


代码参考:http://blog.csdn.net/blankcqk/article/details/47759541


放错代码了,放成参考代码了,现在已经改成我自己从写的代码了。


(感觉夏天就是要和冰冰凉凉的桔子汁,就是用桔子粉泡的那种,http://s.dianping.com/topic/2988138,暴露年纪了惊恐)

#include<stdio.h>#include<string.h>#include<iostream>#include<vector>using namespace std;#define N 100010#define INF 0x3f3f3f3fstruct node{    node *ch[2];//左右孩子节点地址    node *fa;//父节点的地址,但是不同于普通树中父节点的含义    int own;//点的话,等于多少无所谓,所以初始化为0后可不再修改,如果是边的话,就是大的那个数    int mingcd;//点的话初始化为INF,如果是边的话,就初始化为两个点的gcd    node *minnode;//要初始化为自己,它所在的splay树中,以它为根的节点中,mingcd最小的    int rev;//要初始化为0,该节点处孩子节点处于正确情况下,孩子节点的左右孩子节点是否需要交换    void init(){//初始化,如果是点的话就不需要再进行任何修改了,但是如果是边的话,要看情况修改mingcd和own        ch[0]=NULL;        ch[1]=NULL;        fa=NULL;        mingcd=INF;        minnode=this;        rev=0;        own=0;        return;    }    bool isroot(){//判断this这个节点是不是它所在splay树的根节点,并不是判断它是不是整棵树的根节点        return fa==NULL||((fa->ch[0]!=this)&&(fa->ch[1]!=this));    }    int dir(){//使用这个函数前需确定这个点不是它所在的splay树的根节点,并且标志没有积累        return fa->ch[1]==this?1:0;    }    void setn(int d,node *child){//把child设为this的d孩子,d=1时,右孩子,d=0时,左孩子        ch[d]=child;        if(child){           child->fa=this;        }        return;    }    void push_up(){//向上总结,这时即使有些标志没有向下传,也不影响        minnode=this;        if(ch[0]&&(minnode->mingcd>ch[0]->minnode->mingcd)){            minnode=ch[0]->minnode;        }        if(ch[1]&&(minnode->mingcd>ch[1]->minnode->mingcd)){            minnode=ch[1]->minnode;        }        return;    }    void rot(){//旋转,前提是这个点不是它所在splay树的根节点,并且标志没有积累        int d=dir();        node *tempfafa=fa->fa;        if(!(fa->isroot())){            tempfafa->ch[fa->dir()]=this;        }        fa->setn(d,ch[!d]);        setn(!d,fa);        fa=tempfafa;        ch[!d]->push_up();        return;    }    void fswitch(){//交换左右孩子,并且标志左右孩子的孩子要交换。        swap(ch[0],ch[1]);        rev^=1;    }    void push_down(){//标记下传        if(rev){            if(ch[0]){                ch[0]->fswitch();            }            if(ch[1]){                ch[1]->fswitch();            }        }        rev=0;        return;    }    void go(){        if(!isroot()){            fa->go();        }        push_down();        return;    }    void splay(){        go();        while(!isroot()){            if(!(fa->isroot())){                dir()==fa->dir()?fa->rot():rot();            }            rot();        }        push_up();        return;    }    void access(){        for(node *p=this,*q=NULL;p!=NULL;q=p,p=p->fa){            p->splay();            p->setn(1,q);            p->push_up();        }        splay();        return;    }    void cut(){//无论此时整棵树的根节点是谁,access和此时它的父节点cut,所以不一定cut哪条边        access();        ch[0]->fa=NULL;        ch[0]=NULL;        push_up();    }    void make_root(){        access();        fswitch();    }    void cut(node *another){//此时明确要求cut this和another这条边        make_root();        another->cut();    }    void link(node *another){//printf("wo shi da hao ren");        /*another->make_root();        another->fa=this;        another->access();*///可有可无        make_root();        fa=another;    }    node *query(node *another){        make_root();        another->access();        return another->minnode;        /*another->make_root();        access();        return minnode;*/    }};long long int ans[N];vector<int> ver[N];node *tree[N],pool[2*N],*tail;node *newnode(){    tail->init();    tail++;    return tail-1;}void init(int n){    tail=pool;    for(int i=1;i<=n;i++){        tree[i]=newnode();        tree[i]->own=i;    }    for(int i=n;i>=1;i--){        for(int j=i+i;j<=n;j=j+i){            ver[j].push_back(i);        }    }    long long int tempans=0;    for(int i=2;i<=n;i++){        node *p=newnode();        int temp=ver[i][0];        p->own=i;        p->mingcd=temp;        p->link(tree[i]);        p->link(tree[temp]);        tempans=tempans+temp;        /*if(i==4){            node *temptree=tree[4]->query(tree[2]);            printf("%d %d %d\n",temptree->own,temptree->mingcd,temptree->mingcd);        }*/        for(int j=1;j<ver[i].size();j++){            int temp=ver[i][j];            node *temptree=tree[temp]->query(tree[i]);            /*if(temp==1000){                printf("%d %d %d %d %d %d\n",i,j,temp,temptree->own,temptree->mingcd,temptree->mingcd);            }*///错误导致tree[x]->query(tree[y])总是选中tree[y]代表点的这个节点            if(temptree->mingcd<temp){                /*if(i==24){                    printf("%d %d\n",i,temptree->mingcd);                }*/                tempans=tempans-temptree->mingcd;                tempans=tempans+temp;                int t1=temptree->own;                int t2=temptree->mingcd;                temptree->cut(tree[t1]);                temptree->cut(tree[t2]);                temptree->init();                temptree->mingcd=temp;                temptree->own=i;                temptree->link(tree[i]);                temptree->link(tree[temp]);            }        }        ans[i]=tempans;    }    return;}int main(){    int n;    n=100000;    init(n);    while(scanf("%d",&n)!=EOF){        printf("%lld\n",ans[n]);    }}


0 0