zoukankan      html  css  js  c++  java
  • BZOJ 4144 Dijkstra+Kruskal+倍增LCA

    思路:
    先把所有的加油站 push进按weight排序的优先队列里
    对于每个不是加油站的点 找到到它的点的最短路以及它来源的加油站
    如果x和y有边 且x和y加油站的来源不一样 则它可以连边

    跑一边Kruskal

    倍增查一下 搞定了

    (注意图可能不连通)

    //By SiriusRen
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define N 444444
    int n,s,m,Station[N],rec[N],cnt,f[N],fa[N][35],maxx[N][35],T;
    int q,xx,yy,zz,w[N],v[N],first[N],next[N],tot,vis[N],dis[N],deep[N];
    struct Node{
        int from,now,weight;
        Node(){}
        Node(int x,int y,int z){
            from=x,now=y,weight=z;
        }
    }jy,node[N];
    priority_queue<Node>pq;
    bool operator < (Node a,Node b){
        return a.weight>b.weight;
    }
    void add(int x,int y,int z){
        w[tot]=z,v[tot]=y,next[tot]=first[x],first[x]=tot++;
    }
    void Dijkstra(){
        while(!pq.empty()){
            Node t=pq.top();pq.pop();
            if(vis[t.now])continue;
            vis[t.now]=1;
            for(int i=first[t.now];~i;i=next[i])
                if(dis[v[i]]>dis[t.now]+w[i]){
                    dis[v[i]]=dis[t.now]+w[i];
                    rec[v[i]]=t.from;
                    pq.push(Node(t.from,v[i],dis[v[i]]));
                }
        }
    }
    int W[N],V[N],NEXT[N],FIRST[N],TOT;
    void add2(int X,int Y,int Z){
        W[TOT]=Z,V[TOT]=Y,NEXT[TOT]=FIRST[X],FIRST[X]=TOT++;
    }
    int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
    void Kruskal(){
        for(int i=1;i<=n;i++)f[i]=i;
        sort(node+1,node+1+cnt);
        for(int i=cnt;i;i--){
            int fx=find(node[i].now),fy=find(node[i].from);
            if(fx!=fy){
                f[fx]=fy;
                add2(node[i].now,node[i].from,node[i].weight);
                add2(node[i].from,node[i].now,node[i].weight);
            }
        }
    }
    void dfs(int x,int father){
        vis[x]=T;
        for(int i=1;i<=29;i++){
            fa[x][i]=fa[fa[x][i-1]][i-1];
            maxx[x][i]=max(maxx[x][i-1],maxx[fa[x][i-1]][i-1]);
        }
        for(int i=FIRST[x];~i;i=NEXT[i])
            if(V[i]!=father){
                deep[V[i]]=deep[x]+1;
                fa[V[i]][0]=x,maxx[V[i]][0]=W[i];
                dfs(V[i],x);
            }
    }
    int lca(int x,int y){
        int ans=0;
        if(deep[x]<deep[y])swap(x,y);
        for(int i=29;~i;i--)
            if(deep[x]-(1<<i)>=deep[y])
                ans=max(ans,maxx[x][i]);x=fa[x][i];
        if(x==y)return ans;
        for(int i=29;~i;i--)
            if(fa[x][i]!=fa[y][i]){
                ans=max(ans,max(maxx[x][i],maxx[y][i]));
                x=fa[x][i],y=fa[y][i];
            }
        return max(ans,max(maxx[x][0],maxx[y][0]));
    }
    int main(){
        memset(FIRST,-1,sizeof(FIRST));
        memset(first,-1,sizeof(first));
        memset(dis,0x3f,sizeof(dis));
        scanf("%d%d%d",&n,&s,&m);
        for(int i=1;i<=s;i++){
            scanf("%d",&xx);
            dis[xx]=0,Station[xx]=1,rec[xx]=xx;
            pq.push(Node(xx,xx,0));
        }
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&xx,&yy,&zz);
            add(xx,yy,zz),add(yy,xx,zz);
        }
        Dijkstra();
        for(int i=1;i<=n;i++)
            for(int j=first[i];~j;j=next[j])
                if(rec[v[j]]!=rec[i]){
                    node[++cnt].from=rec[i],node[cnt].now=rec[v[j]];
                    node[cnt].weight=dis[i]+w[j]+dis[v[j]];
                }
        Kruskal(),memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++)
            if(Station[i]&&!vis[i])
                T++,dfs(i,-1);
        scanf("%d",&q);
        for(int i=1;i<=q;i++){
            scanf("%d%d%d",&xx,&yy,&zz);
            if(vis[xx]==vis[yy]&&lca(xx,yy)<=zz)puts("TAK");
            else puts("NIE");
        }
    }

    这里写图片描述

  • 相关阅读:
    矩阵
    向量
    Matlab中的基本数据类型介绍
    静态代码块在何时调用
    保留上次访问网站的时间的几种方法
    用ServletContext做一个简单的聊天室
    ServletContext结合Servlet接口中的init()方法和destroy()方法的运用----网站计数器
    用ServletContext读取.properties文件
    用类加载器的5种方式读取.properties文件
    如何用cookie保存用户的登录的密码和用户名
  • 原文地址:https://www.cnblogs.com/SiriusRen/p/6532167.html
Copyright © 2011-2022 走看看