zoukankan      html  css  js  c++  java
  • p1439

    哎就很惨,对着数据模拟改了半个小时后多拿了5分。

    这道题要A是要log级别的算法的,这就让我想到了lca。

    求路径最小值的最大值,那么那些小边如果不是没了就连不到某个点了是不是就不需要了啊?这样删一条边再删一条边就形成了一个最大生成树。

    那么本题的思路最大生成树+lca就出现了。

    先按照边权sort,然后跑克鲁斯卡尔最大生成树,用到的边都放在另一个邻接表里,其他的边全部扔掉。考虑到不一定只有一个树,就安安心心的跑完每一条边就好。

    然后我们做lca和最小边的预处理。我喜欢的fa数组被并查集占用了,就用father凑合一下。lca的求法具体看我的上一篇呦。并且这道题要维护一个minn[i][k]表示从i向上走2^k的最小边。和fa数据转移相似:

    对于边x,y,v:
    minn[y][0]=v;
    minn[y][k]=min(minn[y][k-1],minn[fa[y][k-1]][k-1]);

    考虑到不一定只有一个树,我们对每个深度数组d[]没有被更新过的点都把它作为一个树的根节点做一遍预处理。

    那么对于询问的时候,考虑到不一定在一个树里,要加上一句判断:

    if(get(x)!=get(y))
        return -1;

    然后在x,y跳的时候跟着更新答案即可,在更新的时候要注意一起跳的时候如果有一个为0就不要更新了,否则一定会每个询问都输出0。

    using namespace std;
    int i,tx,ty;
    int m,n,t;
    int fa[10010],father[10010][30],minn[10010][30],d[10010];
    int link[10010];
    int get(int x)
    {
        if(x==fa[x])return x;        
        return fa[x]=get(fa[x]);
    }
    void hebing(int x,int y)
    {
        fa[get(x)]=get(y);
    }
    struct node
    {
        int x,y,v;
        int next;
    }o[100010],a[100010];
    void add(int x,int y,int v)
    {
        t++;
        o[t].x=x;
        o[t].y=y;
        o[t].v=v;
        o[t].next=link[x];
        link[x]=t;
    }
    bool Orz(node a,node y)
    {
        return a.v>y.v;
    }
    int minnn(int a,int b,int c)
    {
        if(b!=0)
            a=min(a,b);
        if(c!=0)
            a=min(a,c);
        return a;
    }
    void bfs(int now)
    {
        stack<int>q;
        q.push(now);d[now]=1;
        while(q.size())
        {
            int x=q.top();q.pop();
            for(int j=link[x];j!=0;j=o[j].next)
            {
                int y=o[j].y;
                if(d[y])continue;
                q.push(y);
                d[y]=d[x]+1;
                father[y][0]=x;
                minn[y][0]=o[j].v;
                for(int k=1;k<=t;k++)
                {
                    father[y][k]=father[father[y][k-1]][k-1];
                    minn[y][k]=min(minn[y][k-1],minn[father[y][k-1]][k-1]);
                }
            }
        }
    }    
    int ask(int x,int y)
    {
        if(get(x)!=get(y))
            return -1;
        if(d[x]>d[y])
            swap(x,y);
        int ans=200000;
        for(int k=20;k>=0;k--)
            if(d[father[y][k]]>=d[x])
            {
                ans=min(ans,minn[y][k]);
                y=father[y][k];
            }
        if(x==y)return ans;
        for(int k=20;k>=0;k--)
            if(father[x][k]!=father[y][k])
            {
                ans=minnn(ans,minn[x][k],minn[y][k]);
                x=father[x][k],y=father[y][k];
            }
        return minnn(ans,minn[x][0],minn[y][0]);
    }
    int main()
    {
        cin>>n>>m;
        for(i=1;i<=m;i++)
            cin>>a[i].x>>a[i].y>>a[i].v;
        for(i=1;i<=n;i++)
            fa[i]=i;
        sort(a+1,a+1+m,Orz);
        for(i=1;i<=m;i++)
        {
            if(get(a[i].x)!=get(a[i].y))
            {
                hebing(a[i].x,a[i].y);
                add(a[i].x,a[i].y,a[i].v);
                add(a[i].y,a[i].x,a[i].v);
            }
        }
        t=(int)log(n*1.0)/log(2.0)+1;
        for(i=1;i<=n;i++)
            if(!d[i])
                bfs(i);
        cin>>m;
        for(i=1;i<=m;i++)
        {
            cin>>tx>>ty;
            cout<<ask(tx,ty)<<endl;
        }
    }

       还有一种克鲁斯卡尔重构树的算法我只得了60分,恳请改错:

            点我跳转

  • 相关阅读:
    Webpack4 入门手册(共 18 章)下
    npm(Node Package Manager)
    C#(99):C# 5.0 新特性(.NET Framework 4.5 与 Visual Studio 2012 )
    C#(99):四、Async和Await使异步编程更简单
    C#(99):三、.NET 4.0基于任务的异步模式(TAP),推荐使用
    C#(99):二、.NET 2.0基于事件的异步编程模式(EAP)
    C#(99):一、.NET 1.0 异步编程模型(APM)
    VS中的代码段功能
    VS在C#类文件头部添加文件注释的方法
    C#(99):C# 语言历史版本特性(C# 1.0到C# 8.0汇总)
  • 原文地址:https://www.cnblogs.com/qywyt/p/9629351.html
Copyright © 2011-2022 走看看