hdu5398(lct维护最大生成树)
2015-08-20 10:31
495 查看
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,暴露年纪了
)
至于为什么只选择一个点是另一个点的整倍数的边,我的理解是:把每条边的权值取相反数,那样求最大生成树,就转化为求最小生成树;假设现在一共有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 0x3f3f3f3f struct 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 ; vector<int> ver ; node *tree ,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 ); } }
相关文章推荐
- 8月Web服务器份额:Apache夺冠 份额持续下降
- Linux makefile的使用变量
- powershell常用操作
- Linux命令_find_查找命令
- 基于OpenCV及连通域分析进行文本块分割 推荐
- linux shell 常用参数 ls top 降序 passwd
- db2top详解
- Linux做一个功能完备的路由器
- shell基础知识
- Linux下查看文件和文件夹大小
- Linux做简单路由器
- Tomcat 7.0.63启动报错
- openwrt mjpeg-stream使用
- JOptionPane类提示框的一些常用的方法
- DropDownList查询&Input(Checkbox)查询
- nginx 部署
- VS2013中如何解决error C4996: 'fopen'问题
- centos7 安装配置ceph
- 解决SVN Can’t open file ‘/XXX/xxx/db/txn-current-lock’错误
- 解决SVN Can’t open file ‘/XXX/xxx/db/txn-current-lock’错误