CF827D,巧妙的图(树)论题

来源:互联网 发布:光纤分路器 什么网络 编辑:程序博客网 时间:2024/06/06 02:22

官方题解是有的,但没有给出具体实现。
首先,我们用kruskal+并查集求出MST
假设点x和y之间是非树边,我一开始想用tarjan+带权并查集求出lca(x,y),以及x到y路径上的边权最值。
然后,暴力将x到y的之间的树边的答案赋成x和y之间的边权,为了保证每个点均摊只赋一次值,我们可以使用并查集来维护一个点到最远的赋过值的祖先。
注意非树边要从小到大处理。
如果真是这样,那这题不就成了并查集好题?
然而tarjan算法中的带权并查集,只能求出其中一个点到lca的边权最大值,这是算法特性所致。发现问题后,我改用了倍增
同时,具体处理非树边对树边的影响时,我并不是如前所述,而是在x和y打上插入标记,在lca(x,y)打上删除标记,用可并堆维护。
于是,并查集*3变成堆+倍增+并查集。

#include<ext/pb_ds/priority_queue.hpp>#include<algorithm>#include<vector>#include<cctype>#include<cstdio>using namespace __gnu_pbds;using std::vector;inline int getint(){    int x=0,f=1;    char c=getchar();    while(!isdigit(c)){        if(c=='-')f=-1;        c=getchar();    }    for(;isdigit(c);c=getchar())x=x*10+c-48;    return x*f;}int buf[100];inline void putint(int x){    if(!x)putchar('0');        else{            if(x<0)putchar('-'),x=-x;            int xb=0;            for(;x;x/=10)buf[++xb]=x%10;            for(;xb;--xb)putchar(buf[xb]+48);        }}const int N=200010; int g[N],n,m,i,ans[N],j,u,v,mi[N];bool b[N];int gfa(int a){    return g[a]==a?a:g[a]=gfa(g[a]);}struct edge{    int u,v,w,id;       bool operator<(const edge&b)const{        return w<b.w;    }}e[N],*ee=e;struct pii{    int first,second;    bool operator<(const pii&x) const{        return first==x.first?second<x.second:first<x.first;    }    bool operator>(const pii&x)const{        return first==x.first?second>x.second:first>x.first;    }}x;pii make_pair(int a,int b){    return (pii){a,b};}inline int max(int a,int b){    return a>b?a:b;}inline void swap(int&a,int&b){    int t=a;    a=b,b=t;}struct tree{    struct edge{        int to,w,id;    };    vector<edge> e[N];    struct node{        int v,x;    };    vector<node> in[N];    vector<int> out[N];    int eid[N],f[N][20],ma[N][20],dep[N];    priority_queue<int,std::greater<int>,pairing_heap_tag> d[N];    priority_queue<int,std::greater<int>,pairing_heap_tag>::point_iterator b[N],a[N];    inline void addedge(int u,int v,int w,int i){        e[u].push_back((edge){v,w,i});        e[v].push_back((edge){u,w,i});    }    void dfs1(int x,int fa,int v){        dep[x]=dep[fa]+1;        *f[x]=fa;        *ma[x]=v;        for(int i=1;i<18;++i)f[x][i]=f[f[x][i-1]][i-1],ma[x][i]=max(ma[x][i-1],ma[f[x][i-1]][i-1]);        for(unsigned int  j=0;j<e[x].size();++j)            if(e[x][j].to!=fa)eid[e[x][j].to]=e[x][j].id,dfs1(e[x][j].to,x,e[x][j].w);    }    void dfs(int x,int fa){        unsigned int i;        for(i=0;i<e[x].size();++i)if(e[x][i].to!=fa)dfs(e[x][i].to,x),d[x].join(d[e[x][i].to]);        for(i=0;i<in[x].size();++i)            if(a[in[x][i].x]==NULL)a[in[x][i].x]=d[x].push(in[x][i].v);                else b[in[x][i].x]=d[x].push(in[x][i].v);        for(i=0;i<out[x].size();++i)d[x].erase(a[out[x][i]]),d[x].erase(b[out[x][i]]);        if(!d[x].empty())ans[ee[eid[x]].id]=d[x].top()-1;    }    pii lca(int x,int y){        if(dep[x]>dep[y])swap(x,y);        int t=dep[y]-dep[x],ans=0,i;        for(i=17;i>=0;--i)if(t&(1<<i))ans=max(ans,ma[y][i]),y=f[y][i];        if(x==y)return make_pair(ans,x);        for(i=17;i>=0;--i)if(f[x][i]!=f[y][i])ans=max(ans,max(ma[x][i],ma[y][i])),x=f[x][i],y=f[y][i];        return make_pair(max(ans,max(*ma[x],*ma[y])),*f[x]);    }}t;int main(){    scanf("%d%d",&n,&m);    for(i=1;i<=m;++i)e[i].u=getint(),e[i].v=getint(),e[e[i].id=i].w=getint(),ans[i]=1<<30;    std::sort(e+1,e+m+1);    for(i=1;i<=n;++i)g[i]=i;    for(i=1;i<=m;++i){        u=gfa(e[i].u);        v=gfa(e[i].v);        if(u!=v){            g[u]=v;            --j;            b[e[i].id]=1;            t.addedge(e[i].u,e[i].v,e[i].w,i);        }    }    t.dfs1(1,0,0);    for(i=1;i<=m;++i)        if(!b[e[i].id]){            x=t.lca(e[i].u,e[i].v);            ans[e[i].id]=x.first-1;            t.in[e[i].u].push_back((tree::node){e[i].w,i});            t.in[e[i].v].push_back((tree::node){e[i].w,i});            t.out[x.second].push_back(i);        }    t.dfs(1,0);    for(i=1;i<=m;++i){        if(ans[i]==1<<30)putchar('-'),putchar('1');            else putint(ans[i]);        putchar(' ');    }    return 0;}
原创粉丝点击