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分,恳请改错:

            点我跳转

  • 相关阅读:
    BZOJ 2034 【2009国家集训队】 最大收益
    vijos P1780 【NOIP2012】 开车旅行
    BZOJ 2115 【WC2011】 Xor
    BZOJ 3631 【JLOI2014】 松鼠的新家
    BZOJ 4717 改装
    BZOJ 2957 楼房重建
    BZOJ 4034 【HAOI2015】 T2
    BZOJ 1834 【ZJOI2010】 network 网络扩容
    BZOJ 2440 【中山市选2011】 完全平方数
    BZOJ 2733 【HNOI2012】 永无乡
  • 原文地址:https://www.cnblogs.com/qywyt/p/9629351.html
Copyright © 2011-2022 走看看