uoj 176. 新年的繁榮
阿新 • • 發佈:2019-01-02
題意:
給出一個完全圖,邊權為兩點權值的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);
}