CF 160D Edges in MST

2 篇文章 0 订阅
2 篇文章 0 订阅

n(10w) 个点 m(10w) 条边的无向联通图,回答每一条边是属于任何一个MST(minimum spanning tree),还是不属于任何一个MST,还是属于至少一个MST。
关于正解。
桥+dsu
By Kyle Young :

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e5+5;
int tot_edge,head[N],dfs_clock,pre[N],par[N],ans[N];
// ans[i]=0:any 1:at least one 2:none
void rd(int &res){
    res=0;
    char c;
    while(c=getchar(),c<48);
    do res=(res<<3)+(res<<1)+(c^48);
        while(c=getchar(),c>47);
}
struct EDGE{
    int u,v,cost,id;
    inline void Rd(){
        rd(u);rd(v);rd(cost);
    }
    inline bool operator <(const EDGE &tmp)const{
        return cost<tmp.cost;
    }
}es[N];
struct Edge{
    int to,nxt,id;
}edge[N<<1];
void add_edge(int u,int v,int id){
    edge[tot_edge]=(Edge){v,head[u],id};
    head[u]=tot_edge++;
}
int get_root(int x){
    return par[x]==x?x:par[x]=get_root(par[x]);
}
inline void Min(int &a,int b){
    if(b<a)a=b;
}
int dfs(int u,int id){
    int lowu=pre[u]=++dfs_clock;
    for(int i=head[u];~i;i=edge[i].nxt){
        int v=edge[i].to;
        if(!pre[v]){
            int lowv=dfs(v,i);
            Min(lowu,lowv);
            if(lowv>pre[u])ans[edge[i].id]=0;
        }
        else if(pre[v]<pre[u]&&i!=(id^1)){
            Min(lowu,pre[v]);
        }
    }
    return lowu;
}
void unite(int u,int v){
    u=get_root(u);
    v=get_root(v);
    if(u==v)return;
    par[u]=v;
}
int main(){
    int n,m;
    rd(n);rd(m);
    for(int i=1;i<=n;++i)
        par[i]=i;
    for(int i=0;i<m;++i){
        es[i].Rd();
        es[i].id=i;
    }
    sort(es,es+m);
    for(int i=0;i<m;){
        int j=i;
        while(j+1<m&&es[j+1].cost==es[j].cost)++j;
        tot_edge=dfs_clock=0;
        for(int k=i;k<=j;++k){
            es[k].u=get_root(es[k].u);
            es[k].v=get_root(es[k].v);
            int u=es[k].u,v=es[k].v;
            head[u]=head[v]=-1;
            pre[u]=pre[v]=0;
        }
        for(int k=i;k<=j;++k){
            int u=es[k].u,v=es[k].v,id=es[k].id;
            if(u==v){
                ans[id]=2;
                continue;
            }
            ans[id]=1;
            add_edge(u,v,id);
            add_edge(v,u,id);
        }
        for(int k=i;k<=j;++k){
            if(!pre[es[k].u])dfs(es[k].u,-1);
        }
        for(;i<=j;++i)
            unite(es[i].u,es[i].v);
    }
    for(int i=0;i<m;++i){
        if(ans[i]==2)puts("none");
        else puts(ans[i]?"at least one":"any");
    }
    return 0;
}

关于树链剖分水过。

By ShinFeb(me)

#include<cmath>
#include<queue>
#include<stack>
#include<cstdio>
#include<cstring>
#include<complex>
#include<iostream>
#include<algorithm>
#define pi acos(-1)
#define inf (1<<30)
#define INF (1<<62)
#define CLR(x,f) memset(x,f,sizeof(x))
#define CPY(x,y) memcpy(x,y,sizeof(x))
#define prt(x) cout<<#x<<": "<<x<<endl
#define huh(x) printf("--------DEBUG(%d)--------\n",x)
#define travel(x) for(Edge *e=h[x];e;e=e->n)
//#define TL
using namespace std;
const int M=100005;

int ans[M],n,m;

struct Edge{
    Edge *n;
    int to,c,id;
    Edge(){}
}*h[M];
inline void addEdge(int u,int v,int w,int id){
    Edge *x=new Edge();
    x->to=v;x->c=w;x->n=h[u];x->id=id;
    h[u]=x;
}

struct EDGE{
    int u,v,w,id;
    bool operator<(const EDGE&a)const{
        return w<a.w;
    }
}edge[M];

int val[M],link[M],par[M];
int sz[M],dep[M];
int frm[M];
int segID[M],dfsID[M];
//dfs序->sgm sgm->dfs序 
int dfs_clock;

void dfs(int x,int f){
    sz[x]=1;par[x]=f;dep[x]=dep[f]+1;
    travel(x)if(e->to!=f){
        val[e->to]=e->c;
        frm[e->to]=e->id;
        dfs(e->to,x);
        sz[x]+=sz[e->to];
    }
}

void assign(int x,int l){
    link[x]=l;
    segID[x]=++dfs_clock;
    dfsID[dfs_clock]=x;
    int k=0;
    travel(x)if(sz[e->to]<sz[x]&&sz[e->to]>sz[k])k=e->to;
    if(!k)return;
    assign(k,l);
    travel(x)if(sz[e->to]<sz[x]&&e->to!=k)assign(e->to,e->to);
}

struct node{
    int mx,id;
    node(){}
    node(int mx_,int id_):mx(mx_),id(id_){}
    bool operator<(const node&a)const{
        if(mx!=a.mx)return mx<a.mx;
        return id<a.id;
    }
};
void Max(node &x,node y){
    if(x<y)x=y;
}
struct Segment{
    node v[M<<2];
    void up(int x){
        v[x]=max(v[x<<1],v[x<<1|1]);
    }
    void build(int l,int r,int x){
        if(l==r){
            v[x].mx=val[dfsID[l]];
            v[x].id=dfsID[l];
            return;
        }
        int mid=l+r>>1;
        build(l,mid,x<<1);
        build(mid+1,r,x<<1|1);
        up(x);
    }
    void clear(int l,int r,int x,int t){
        if(l==r){
            v[x].id=0;
            return;
        }
        int mid=l+r>>1;
        if(t<=mid)clear(l,mid,x<<1,t);
        else clear(mid+1,r,x<<1|1,t);
        up(x);
    }
    node query(int l,int r,int x,int L,int R){
        if(L<=l&&r<=R)return v[x];
        int mid=l+r>>1;
        node res=node(0,0);
        if(L<=mid)Max(res,query(l,mid,x<<1,L,R));
        if(R>mid)Max(res,query(mid+1,r,x<<1|1,L,R));
        return res;
    }
}sgm;

int fa[M];
int get(int x){
    return fa[x]==x?x:fa[x]=get(fa[x]);
}

void buildMST(){
    sort(edge+1,edge+m+1);
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++){
        int u=edge[i].u,v=edge[i].v;
        if(get(u)==get(v))continue;
        fa[get(u)]=get(v);
        ans[edge[i].id]=true;
        addEdge(u,v,edge[i].w,edge[i].id);
        addEdge(v,u,edge[i].w,edge[i].id);
    }
}

void HLD(){
    dfs(1,0);
    assign(1,1);
    sgm.build(1,n,1);
}

bool chk(int u,int v,int w){//check u-v的路径上是否有边权==w的边 
    bool flag=false;
    while(link[u]!=link[v]){//取尾不取首 
        if(dep[link[u]]<dep[link[v]])swap(u,v);
        node res=sgm.query(1,n,1,segID[link[u]],segID[u]);
        if(res.mx==w){
            while(res.id){
                ans[frm[res.id]]=2;
                sgm.clear(1,n,1,segID[res.id]);
                res=sgm.query(1,n,1,segID[link[u]],segID[u]);
            }
            flag=true;
        }
        u=par[link[u]];
    }
    if(u==v)return flag;
    if(dep[u]<dep[v])swap(u,v);
    node res=sgm.query(1,n,1,segID[v]+1,segID[u]);
    if(res.mx==w){
        while(res.id){
            ans[frm[res.id]]=2;
            sgm.clear(1,n,1,segID[res.id]);
            res=sgm.query(1,n,1,segID[v]+1,segID[u]);
        }
        flag=true;
    }
    return flag;
}

void solve(){
    for(int i=1;i<=m;i++)
        if(!ans[edge[i].id])//非树边 
            if(chk(edge[i].u,edge[i].v,edge[i].w))ans[edge[i].id]=2;
}

int main(){
#ifdef TL
#endif
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
        edge[i].id=i;
    }
    buildMST();
    HLD();
    solve();
    for(int i=1;i<=m;i++){
        if(ans[i]==0)puts("none");
        else if(ans[i]==1)puts("any");
        else puts("at least one");
    }
    return 0;
}

还有一份 的代码。
By ShinFeb again
dsu+dfs序

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int M=50005;
struct Edge{
    int a,b,c,id;
    bool operator<(const Edge&t)const{
        return c<t.c;
    }
}edge[M<<2]; 
struct EDGE{
    int to,nxt;
}e[M<<1];
int n,m;
int mark[M<<2],size[M];
int fa[M],cov[M],par[M];
int last[M],allc,dep[M];
int pos[M<<2];
void ins(int a,int b){
    e[++allc]=(EDGE){b,last[a]};last[a]=allc;
    e[++allc]=(EDGE){a,last[b]};last[b]=allc;
} 
int get(int a){
    return fa[a]==a?a:fa[a]=get(fa[a]);
}
void dfs(int x,int f){
    fa[x]=x;par[x]=f;dep[x]=dep[x]=dep[f]+1;
    for(int i=last[x];i;i=e[i].nxt)
        if(e[i].to!=f)dfs(e[i].to,x);
}
void col(int a,int b,int c){
    while(a=get(a),b=get(b),a!=b){
        if(dep[a]<dep[b])swap(a,b);
        cov[a]=c;fa[a]=par[a];
    }
}
int judge(){
    for(int i=1;i<=n;i++)fa[i]=i,size[i]=1;
    int cost=0;
    for(int i=1;i<=m;i++){
        int a=edge[i].a,b=edge[i].b;
        a=get(a),b=get(b);
        if(a==b)continue;
        mark[i]=1;
        ins(edge[i].a,edge[i].b);
        fa[a]=b;size[b]+=size[a];
        cost+=edge[i].c;
    }
    return size[get(1)]==n?cost:0;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int a,b,c,i=1;i<=m;i++){
        scanf("%d%d%d",&a,&b,&c);
        edge[i]=(Edge){a,b,c,i};
    }
    sort(edge+1,edge+m+1);
    int ans=judge();
    if(!ans){
        for(int i=0;i<m;i++)puts("-1");
        return 0;
    }
    for(int i=1;i<=m;i++)
        pos[edge[i].id]=i;
    dfs(1,0);
    for(int i=1;i<=m;i++)
        if(!mark[i])
            col(edge[i].a,edge[i].b,i); 
    for(int i=1;i<=m;i++){
        if(!mark[pos[i]]){
            printf("%d\n",ans);
            continue;
        }
        int a=edge[pos[i]].a,b=edge[pos[i]].b;
        if(dep[a]<dep[b])a=b;
        if(!cov[a])puts("-1");
        else printf("%d\n",ans-edge[pos[i]].c+edge[cov[a]].c);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值