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

Posted zinn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1977 [BeiJing2010组队]次小生成树 Tree——严格次小生成树相关的知识,希望对你有一定的参考价值。

题目: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——严格次小生成树的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 1977 [BeiJing2010组队]次小生成树 Tree

BZOJ 1977 [BeiJing2010组队]次小生成树 Tree

严格次小生成树(Bzoj1977:[Beijing2010组队]次小生成树)

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

bzoj1977[BeiJing2010组队]次小生成树 Tree 权值线段树合并

1977: [BeiJing2010组队]次小生成树 Tree