zoukankan      html  css  js  c++  java
  • HDU 5398 GCD Tree

    题目链接

    题意:

    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.

    有n个点,将这些点建树,如果u与v之间有边相连,其边权为gcd(u,v) 请你找到一种建树的方案使边权和最大,对于每次询问的n,输出最大的边权和

    思路:

    首先,每一次加入一个点,只有和它的约数相连才会有贡献。比如当加入6的时候,优先考虑的应该是和3或2相连而不会去和5相连。

    刚开始以为每一次直接和最大的因子相连贡献最大,但是这样子很显然是有问题的。

    当加入一个点 6时,第一个考虑和3相连此时6的贡献为3,如果将1和3的边断掉,将6与2相连后再将3接到6上,边权和会更大

    由此可见问题就转换成了求最大生成树。

    先考虑每个点只会与它的因子相连的时候存在贡献,那么对于点对(x,y) 来说(这里y是x的因子),存在两种情况:

    1、如果x与y不在一棵树上,那么可以将其直接连接。

    2、如果x与y​此时已经在一棵树上,那么直接加边显然会构成环。此时我们可以删掉路径中的一条边,再将这两个点相连。由于要使得答案变大,那么删掉的边的价值一定是要小于当前加入的价值,也就是说我们要找到路径最小的边权

    路径上求最大最小很明显可以用LCT了这可是件好事情

    然后由于是边权,可以将边转换为点,分别向两端连边。

    #include<bits/stdc++.h>
    #define M 100005
    #define N 400005
    #define ll long long
    using namespace std;
    int n,val[N],Mi[N],son[N][2],fa[N],rev[N],L[N],R[N];
    vector<int>G[M];
    ll Ans[M];
    //LCT板子
    #define ls son[x][0]
    #define rs son[x][1]
    bool Is(int x) {
    	return (son[fa[x]][0]==x)||(son[fa[x]][1]==x);
    }
    bool chk(int x) {
    	return son[fa[x]][1]==x;
    }
    void up(int x) {
    	Mi[x]=x;
    	if(val[Mi[ls]]<val[Mi[x]])Mi[x]=Mi[ls];
    	if(val[Mi[rs]]<val[Mi[x]])Mi[x]=Mi[rs];
    }
    void reserve(int x) {
    	if(!x)return;
    	swap(ls,rs),rev[x]^=1;
    }
    void down(int x) {
    	if(!rev[x])return;
    	reserve(ls),reserve(rs),rev[x]=0;
    }
    void rotate(int x) {
    	int y=fa[x],z=fa[y],k=chk(x),w=son[x][k^1];
    	if(Is(y))son[z][chk(y)]=x;
    	fa[x]=z,son[y][k]=w;
    	if(w)fa[w]=y;
    	son[x][k^1]=y,fa[y]=x;
    	up(y),up(x);
    }
    int stk[M];
    void splay(int x) {
    	int tot=0,y=x;
    	stk[++tot]=y;
    	while(Is(y))stk[++tot]=fa[y],y=fa[y];
    	while(tot)down(stk[tot--]);
    	while(Is(x)) {
    		int y=fa[x],z=fa[y];
    		if(Is(y)) {
    			if(chk(x)==chk(y))rotate(y);
    			else rotate(x);
    		}
    		rotate(x);
    	}
    }
    void access(int x) {
    	for(int y=0; x; y=x,x=fa[x])
    		splay(x),son[x][1]=y,up(x);
    }
    void makert(int x) {
    	access(x),splay(x),reserve(x);
    }
    int rt(int x) {
    	access(x),splay(x);
    	down(x);
    	while(ls)x=ls,down(x);
    	return x;
    }
    int Query(int x,int y) {
    	makert(x),access(y),splay(y);
    	return Mi[y];
    }
    void link(int x,int y) {
    	makert(x),fa[x]=y;
    }
    void cut(int x,int y) {
    	makert(x),access(y),splay(y),fa[son[y][0]]=0,son[y][0]=0,up(y);
    }
    int main() {
    	for(int i=1; i<M; i++)//预处理出来因子
    		for(int j=i; j<M; j+=i)
    			G[j].push_back(i);
    	int now=0;
    	val[0]=1e8;
    	for(int i=1; i<M; i++) { //[1,n]的点
    		val[++now]=1e8;
    		Mi[now]=now;
    	}
    	ll tmp=0;
    	for(int u=1; u<M; u++) {
    		for(int j=G[u].size()-2; j>=0; j--) {
    			int v=G[u][j];
    			bool ok=1;
    			if(rt(u)==rt(v)) {//如果已经相连考虑删边
    				int k=Query(u,v);
    				if(val[k]<v) {
    					cut(L[k],k),cut(R[k],k);
    					tmp-=val[k];
    					ok=1;
    				} else ok=0;
    			}
    			if(ok) {//说明可以连边
    				val[++now]=v,Mi[now]=now,L[now]=u,R[now]=v;
    				link(u,now),link(v,now);
    				tmp+=v;
    			}
    		}
    		Ans[u]=tmp;
    	}
    	while(~scanf("%d",&n))printf("%lld
    ",Ans[n]);
    	return 0;
    }
    
  • 相关阅读:
    Autofac小例子
    Spring自带mock测试Controller
    [转载]转Java 几个memcached 连接客户端对比 选择
    danga的MemcachedClient的几个缺陷
    linux查看memcached状态
    Linux下配置安装PHP环境(Apache2)
    使用memcache.php监控memcached
    memcached运行情况监测
    memcached监控的几种方法(nagios等)
    xmemcached使用的几点优化建议
  • 原文地址:https://www.cnblogs.com/cly1231/p/10784486.html
Copyright © 2011-2022 走看看