码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj1977 [BeiJing2010组队]次小生成树 Tree——严格次小生成树

时间:2018-07-07 00:30:49      阅读:214      评论:0      收藏:0      [点我收藏+]

标签:ring   scanf   blank   pac   怎么   div   ons   nbsp   space   

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1977

因为严格,所以要记录到 LCA 的一个次小值;

很快写好,然后改掉一堆错误后终于过了样例!然而交上去1WA;

又改了半天,还是WA,于是放弃,抄题解好久...

然而就在我调了一个小时终于锁定错误就在那个子函数里的时候才突然看到了自己的明显惊天大错误是怎么回事??!!!稍微改了一下下就完美AC。。。

不过还有点收获,把求各种层次的 f 放在 dfs 函数里会比单独拿出来再求一遍快 1000+ms 哦~

题解的写法是直接看 u 到 lca 和 v 到 lca 路上的值,而我是求 lca 的过程中求值的,还是喜欢我的写法;

题解的写法放在注释里了;

囧。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const maxn=1e5+5,maxm=3e5+5,inf=1e9;
int n,m,f[maxn][22],dep[maxn],mx[maxn][22],nmx[maxn][22];//22
int hd[maxn],ct,fa[maxn],d[maxn],mnn;
ll ans;//ll
bool vis[maxn],used[maxm];
struct P{int u,v,w;}e[maxm];
struct T{
    int mx,nmx;
    T(int x=0,int n=0):mx(x),nmx(n) {}
};
struct N{
    int to,nxt,w;
    N(int t=0,int n=0,int w=0):to(t),nxt(n),w(w) {}
}ed[maxn<<1];
bool cmp(P x,P y){return x.w<y.w;}
void add(int x,int y,int w){ed[++ct]=N(y,hd[x],w); hd[x]=ct;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void dfs(int x)
{
    for (int i=1; i<=20; i++)//写在这里较快 
        {
            if(dep[x]<(1<<i))break;
            f[x][i]=f[f[x][i-1]][i-1];
            mx[x][i]=max(mx[x][i-1],mx[f[x][i-1]][i-1]);
            if (mx[x][i-1]==mx[f[x][i-1]][i-1])
                nmx[x][i]=max(nmx[x][i-1],nmx[f[x][i-1]][i-1]);
            else
                nmx[x][i]=min(mx[x][i-1],mx[f[x][i-1]][i-1]),
                nmx[x][i]=max(nmx[x][i],nmx[x][i-1]),
                nmx[x][i]=max(nmx[x][i],nmx[f[x][i-1]][i-1]);
        }
    vis[x]=1;
    for(int i=hd[x],u;i;i=ed[i].nxt)
        if(!vis[u=ed[i].to])
        {
            f[u][0]=x; dep[u]=dep[x]+1;
            mx[u][0]=ed[i].w;
//            nmx[u][0]=ed[i].w;//无! 
            d[u]=ed[i].w;
            dfs(u);
        }
}
void init()
{
    dep[1]=1; dfs(1);
//    for(int j=1;j<=20;j++)
//        for(int i=1;i<=n;i++)
//        {
//            int tmx=mx[f[i][j-1]][j-1],tnx=nmx[f[i][j-1]][j-1];
//            f[i][j]=f[f[i][j-1]][j-1];
//            mx[i][j]=max(mx[i][j-1],tmx);
//            if(tmx>mx[i][j-1]) nmx[i][j]=max(mx[i][j-1],tnx);
//            else if(tmx==mx[i][j-1]) nmx[i][j]=max(nmx[i][j-1],tnx);
//            else nmx[i][j]=max(nmx[i][j-1],tmx);
//        }
}
void ch(int &rmx,int &rnx,int tmx,int tnx)
{
    if(tmx>rmx)
    {
        rnx=max(tnx,rmx);
        rmx=tmx;
    }
    else if(tmx==rmx) rnx=max(tnx,rnx);
    else rnx=max(rnx,tmx);
}
T lca(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);
    int k=dep[x]-dep[y],rmx=-1,rnx=-1;
    for(int i=20;i>=0;i--)
//        if((1<<i)&k){rmx=mx[x][i]; rnx=nmx[x][i]; x=f[x][i];}//x放在后面修改! 
        if((1<<i)&k){ch(rmx,rnx,mx[x][i],nmx[x][i]); x=f[x][i];}//!!!!!!囧 
    for(int i=20;i>=0;i--)
        if(f[x][i]!=f[y][i])
        {
            ch(rmx,rnx,mx[x][i],nmx[x][i]);
            ch(rmx,rnx,mx[y][i],nmx[y][i]);
            x=f[x][i]; y=f[y][i]; //后面改!! 
        }
    if(x!=y) ch(rmx,rnx,max(d[x],d[y]),min(d[x],d[y]));
    return T(rmx,rnx);
}
//int LCA(int x,int y)
//{
//    if(dep[x]<dep[y])swap(x,y);
//    int k=dep[x]-dep[y];
//    for(int i=20;i>=0;i--)
//        if((1<<i)&k){rmx=mx[x][i]; rnx=nmx[x][i]; x=f[x][i];} 
//    for(int i=20;i>=0;i--)
//        if(f[x][i]!=f[y][i])
//        {
//            x=f[x][i]; y=f[y][i];
//        }
//    if(x==y)return x;
//    return f[x][0];
//}
//T work(int x,int lca)
//{
//    T ret;
//    int maxx1=-1,maxx2=-1;
//    int d=dep[x]-dep[lca];
//    for (int i=0; i<=20; i++)
//        if (d&(1<<i))
//            {
//                ch(maxx1,maxx2,mx[x][i],nmx[x][i]);
//                x=f[x][i];
//            }
//    ret.mx=maxx1,ret.nmx=maxx2;
//    return ret;
//}
//T solve(int x)
//{
//    T ret;
//    int u=e[x].u,v=e[x].v,lca=LCA(u,v);
//    T uu=work(u,lca);
//    T vv=work(v,lca);
//    ret.mx=max(uu.mx,vv.mx);
//    if(uu.mx>vv.mx) ret.nmx=max(vv.mx,uu.nmx);
//    else if(uu.mx==vv.mx) ret.nmx=max(vv.nmx,uu.nmx);
//    else ret.nmx=max(uu.mx,vv.nmx);
//    return ret;
//}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=n;i++)fa[i]=i;
    int cnt=0;
    for(int i=1,u,v;i<=m;i++)
        if(find(u=e[i].u)!=find(v=e[i].v))
        {
            cnt++;
            fa[find(u)]=find(v);
            used[i]=1; ans+=e[i].w;
            add(u,v,e[i].w); add(v,u,e[i].w);
            if(cnt==n-1)break;
        }
    init(); 
    mnn=inf;
    for(int i=1;i<=m;i++)
    {
        if(used[i])continue;
        int u=e[i].u,v=e[i].v;
        T l=lca(u,v);
//        T l=solve(i);
        if(e[i].w==l.mx)mnn=min(mnn,e[i].w-l.nmx);
        else mnn=min(mnn,e[i].w-l.mx);
    }
    printf("%lld",ans+mnn);
    return 0;
}

 

bzoj1977 [BeiJing2010组队]次小生成树 Tree——严格次小生成树

标签:ring   scanf   blank   pac   怎么   div   ons   nbsp   space   

原文地址:https://www.cnblogs.com/Zinn/p/9275905.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!