zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    CF666E Forensic Examination 广义后缀自动机 + 线段树合并 + 树上倍增
    NOI2018 你的名字 后缀自动机 + 线段树合并 + 可持久化
    [NOI2018]你的名字(68pts) 后缀自动机
    [SDOI2016]生成魔咒 后缀自动机
    洛谷P3369 【模板】普通平衡树 01trie/骚操作
    BZOJ2161: 布娃娃 整体二分
    超市购物功能,会员卡功能,会员卡积分查询功能,会员卡奖品功能,自己练手函数程序
    可变长参数,函数的嵌套,名称空间,关键字
    函数基础,函数返回值,函数调用的3中方式,形参与实参
    文件的详细操作
  • 原文地址:https://www.cnblogs.com/Zinn/p/9275905.html
Copyright © 2011-2022 走看看