BZOJ2753: [SCOI2012]滑雪与时间胶囊

来源:互联网 发布:淘宝店免费装修教程 编辑:程序博客网 时间:2024/04/28 06:21

可以发现要求的是一个有向图的最小生成树(最小树形图)
如果是普通的DAG,可以每个点贪心选最小入度,
但这个有向图满足一个特性,即边都是从高的点连向低的点或相同高度的点,在相同高度有环
直接按无向图用kruskal之所以不行,是因为会出现下图情况
这里写图片描述
先访问了a->b,再访问c->b且此时c不在最小生成树中,那这条有向边本来无法拓展,但被当作无向边拓展了
于是考虑避免这种情况,先只处理起点能到达的节点,然后将边按终点高度第一关键字排序,边权为第二关键字排序,就可以避免上图的非法情况,直接用kruskal了

code:

#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long longusing namespace std;inline void read(int &x){    char c;    while(!((c=getchar())>='0'&&c<='9'));    x=c-'0';    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';}inline void swap(int &x,int &y){x^=y;y^=x;x^=y;}const int maxn = 1100000;const int maxm = 2100000;int n,m;struct edge{    int y,nex;}a[maxm]; int len,fir[maxn];inline void ins(const int x,const int y){    a[++len].y=y; a[len].nex=fir[x]; fir[x]=len;}struct node{    int dx,x,y,c;    node(){}    node(const int &_dx,const int &_x,const int &_y,const int &_c){dx=_dx;x=_x;y=_y;c=_c;}}e[maxm];inline bool cmp(node x,node y){return x.dx==y.dx?x.c<y.c:x.dx>y.dx;}queue<int>q;bool v[maxn];int ansn=0;void bfs(){    q.push(1); v[1]=true;    while(!q.empty())    {        const int x=q.front(); q.pop();         ansn++;        for(int k=fir[x];k;k=a[k].nex)        {            const int y=a[k].y;            if(!v[y]) v[y]=true,q.push(y);        }    }}int h[maxn];int f[maxn];int find_(const int x){    if(f[x]==x) return x;    return f[x]=find_(f[x]);}int main(){    len=0; // memset(fir,0,sizeof fir);    read(n); read(m);    for(int i=1;i<=n;i++) read(h[i]);    for(int i=1;i<=m;i++)    {        int x,y,c;read(x); read(y); read(c);        if(h[x]<h[y]) swap(x,y);        ins(x,y);        if(h[x]==h[y]) ins(y,x);        e[i]=node(h[y],x,y,c);    }    bfs();    sort(e+1,e+m+1,cmp);    for(int i=1;i<=n;i++) f[i]=i;    ll ans=0;    for(int i=1;i<=m;i++)    {        int x=e[i].x,y=e[i].y,c=e[i].c;        if(v[x]&&v[y])        {            int f1=find_(x),f2=find_(y);            if(f1!=f2) ans+=c,f[f1]=f2;        }    }    printf("%d %lld\n",ansn,ans);    return 0;}
0 0
原创粉丝点击