zoukankan      html  css  js  c++  java
  • LOJ #2876. 「JOISC 2014 Day2」水壶 BFS+最小生成树+倍增LCA

    非常好的一道图论问题.  

    显然,我们要求城市间的最小生成树,然后查询路径最大值.    

    然后我们有一个非常神的处理方法:进行多源 BFS,处理出每一个城市的管辖范围.     

    显然,如果两个城市的管辖范围没有交集的话连边一定不是优秀的(一定会有一种都在管辖范围之内的连边方式来代替这种连边方式)   

    然后由于每一个点只属于一个城市的管辖范围,所以每个点只会扩展一次,这个 BFS 的复杂度是线性的. 

    code:

    #include <bits/stdc++.h>  
    #define N 2006  
    #define M 200005 
    #define ll long long   
    using namespace std; 
    namespace IO {  
        void setIO(string s) {
            string in=s+".in"; 
            string out=s+".out"; 
            freopen(in.c_str(),"r",stdin); 
            // freopen(out.c_str(),"w",stdout);  
        }
    };      
    char str[N];
    int n,m,P,Q,edges; 
    int dep[M]; 
    int hd[M],to[M<<1],nex[M<<1],val[M<<1],vis[M],fa[18][M],Max[18][M];       
    int wall[N][N],id[N][N],dis[N][N],bel[N][N],p[N*N];     
    int dx[]={-1,0,1,0};   
    int dy[]={0,1,0,-1};   
    struct node { 
        int x,y; 
        node(int x=0,int y=0):x(x),y(y){}   
    };   
    struct edge {
        int x,y; 
        edge(int x=0,int y=0):x(x),y(y){}  
    };   
    queue<node>q;   
    vector<edge>G[N*N];        
    void add(int u,int v,int c) {
        nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c;  
    }         
    void init() {
        for(int i=0;i<N*N;++i) p[i]=i;  
    }
    int find(int x) {
        return p[x]==x?x:p[x]=find(p[x]);  
    }
    int merge(int x,int y) {
        x=find(x); 
        y=find(y);   
        if(x==y) 
            return 0;    
        p[x]=y;  
        return 1;   
    }
    void dfs(int x,int ff) {
        vis[x]=1;
        fa[0][x]=ff; 
        dep[x]=dep[ff]+1;     
        for(int i=1;i<18;++i) 
            fa[i][x]=fa[i-1][fa[i-1][x]];   
        for(int i=1;i<18;++i) 
            Max[i][x]=max(Max[i-1][fa[i-1][x]],Max[i-1][x]);  
        for(int i=hd[x];i;i=nex[i]) { 
            int v=to[i];   
            if(v!=ff) 
                Max[0][v]=val[i],dfs(v,x);       
        }  
    }
    int query(int x,int y) { 
        int ma=0,i,j;    
        if(dep[x]!=dep[y]) {
            if(dep[y]<dep[x]) swap(x,y);     
            for(i=17;i>=0;--i) {                                                                       
                if(dep[fa[i][y]]>=dep[x]) {
                    ma=max(ma,Max[i][y]);    
                    y=fa[i][y];       
                }
            }
        }
        if(x==y) return ma;      
        for(i=17;i>=0;--i) {
            if(fa[i][y]!=fa[i][x]) {
                ma=max(ma,max(Max[i][y],Max[i][x]));   
                x=fa[i][x],y=fa[i][y];   
            }  
        }
        return max(ma,max(Max[0][y],Max[0][x]));    
    }
    int main() { 
        // IO::setIO("input");  
        int i,j,idx=0;   
        scanf("%d%d%d%d",&n,&m,&P,&Q);     
        for(i=1;i<=n;++i) { 
            scanf("%s",str+1);   
            for(j=1;j<=m;++j) {   
                id[i][j]=++idx;               
                wall[i][j]=(str[j]=='#');    
            }
        }                 
        for(i=1;i<=P;++i) {
            int x,y; 
            scanf("%d%d",&x,&y);   
            bel[x][y]=i;         
            q.push(node(x,y));   
        }     
        while(!q.empty()) {
            node e=q.front(); q.pop();  
            int x=e.x,y=e.y;      
            for(i=0;i<4;++i) {
                int X=x+dx[i],Y=y+dy[i];      
                if(id[X][Y]&&!wall[X][Y]) {         
                    if(!bel[X][Y]) {
                        bel[X][Y]=bel[x][y];  
                        dis[X][Y]=dis[x][y]+1; 
                        q.push(node(X,Y));   
                    }
                    else if(bel[X][Y]!=bel[x][y]){    
                        G[dis[X][Y]+dis[x][y]].push_back(edge(bel[X][Y],bel[x][y]));   
                    }
                }
            }
        }      
        init();   
        for(i=0;i<N*N;++i) {
            for(j=0;j<G[i].size();++j) {
                int u=G[i][j].x,v=G[i][j].y;       
                if(merge(u,v)) { 
                    add(u,v,i);   
                    add(v,u,i);   
                }
            }
        }   
        for(i=1;i<=P;++i) {
            if(!vis[i]) {
                dfs(i,0);   
            }
        }
        for(i=1;i<=Q;++i) {
            int x,y; 
            scanf("%d%d",&x,&y);    
            if(find(x)!=find(y)) 
                printf("-1
    ");  
            else 
                printf("%d
    ",query(x,y));   
        }
        return 0;
    }
    

      

  • 相关阅读:
    计算两个日期相差的天数
    获取当前星期几
    window下重置mysql用户密码
    window下安装mysql
    oracle用户密码过期如何处理?
    awk
    RunLoop
    通知中心
    KVO
    多线程
  • 原文地址:https://www.cnblogs.com/guangheli/p/12375731.html
Copyright © 2011-2022 走看看