1. 程式人生 > >uoj 176. 新年的繁榮

uoj 176. 新年的繁榮

題意:

給出一個完全圖,邊權為兩點權值的and,求最大生成樹。

題解:

這題用最小生成樹的Boruvka演算法。
大概就是每次找到每一個聯通塊權值最大的邊,將這些聯通塊合併,直到只剩一個聯通塊。因為每次聯通塊的個數至少減半,所以只會做log次操作。
那麼這題相當於每個點有不同顏色,要找到每個點的異色點中最大的and值。
題解
code:

#include<cstdio>
#include<cstdlib>
#include<cstdlib>
#include<iostream>
#define LL long long
using namespace std;
int
n,m,fa[100010]; int a[100010]; int findfa(int x) {return fa[x]==x?x:fa[x]=findfa(fa[x]);} struct node{ int max,min; node() {max=0;min=100000;} node(int x,int y) {max=x;min=y;} }mx[100010]; struct trnode{ int lc,rc; node c; }tr[1000010];int tot,root; int new_node() { int x=++tot; tr[x].lc=tr[x].rc=tr
[x].c.max=0;tr[x].c.min=n; return x; } node update(node lc,node rc) { node ans; ans.max=max(lc.max,rc.max); ans.min=min(lc.min,rc.min); return ans; } void cmin(int &x,int y) {x=x<y?x:y;} void cmax(int &x,int y) {x=x>y?x:y;} void ins(int &x,int dep,int c,int id) { if
(!x) x=new_node(); cmin(tr[x].c.min,id);cmax(tr[x].c.max,id); if(dep<0) return; if(c&(1<<dep)) ins(tr[x].rc,dep-1,c,id); else ins(tr[x].lc,dep-1,c,id); } int merge(int x,int y) { if(!y) return x; if(!x) x=new_node(); tr[x].c=update(tr[x].c,tr[y].c); tr[x].lc=merge(tr[x].lc,tr[y].lc); tr[x].rc=merge(tr[x].rc,tr[y].rc); return x; } node findans(int x,int dep,int c,int id) { if(dep<0) return node(0,tr[x].c.min==id?tr[x].c.max:tr[x].c.min); node ans; if(c&(1<<dep)) if(tr[x].rc&&(id!=tr[tr[x].rc].c.min||id!=tr[tr[x].rc].c.max)) ans=findans(tr[x].rc,dep-1,c,id),ans.max+=(1<<dep); else ans=findans(tr[x].lc,dep-1,c,id); else ans=findans(tr[x].lc,dep-1,c,id); return ans; } void dfs(int x,int dep) { if(dep<0) return; if(tr[x].lc) dfs(tr[x].lc,dep-1); if(tr[x].rc) dfs(tr[x].rc,dep-1); tr[x].lc=merge(tr[x].lc,tr[x].rc); } void build() { tot=0;root=new_node(); for(int i=1;i<=n;i++) ins(root,m-1,a[i],findfa(i)); dfs(root,m-1); } int main() { scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]),fa[i]=i; int now=n;LL ans=0; while(now>1) { build(); for(int i=1;i<=n;i++) mx[i]=node(-1,0); for(int i=1;i<=n;i++) { node u=findans(root,m-1,a[i],findfa(i)); if(u.max>mx[findfa(i)].max) mx[findfa(i)]=u; } for(int i=1;i<=n;i++) if(fa[i]==i) { int x=findfa(mx[i].min); if(x!=i) fa[i]=x,now--,ans+=mx[i].max; } } printf("%lld",ans); }