GCPC2018 Problem M: Mountaineers

https://codeforces.com/group/NVaJtLaLjS/contest/253993/attachments
題意:
n*m個點,每個點有一個高度,q個詢問,每次問兩點之間最小的路徑最大值。
思路:把表格看成一張圖,和洛谷P1967是一樣的。https://blog.csdn.net/Wen_Yongqi/article/details/101546392
都是無向圖+詢問多次兩點間距離最大(小)的最小(大)值,用mst+lca解決。

#include<bits/stdc++.h>
using namespace std;

int n,m,q,cnt;
int a[505][505];
int x[1000000],y[1000000],z[1000000];
int p[300000],e[1000000];
vector<int> G[300000];
struct Edge{
    int from,to,dist;
};
vector<Edge> edges;
int fa[300000][20],maxcost[300000][20],deep[300000],vis[300000];

int findset(int x){return x==p[x]?x:p[x]=findset(p[x]);}

bool cmp(int a,int b){return z[a]<z[b];}

void AddEdge(int x,int y,int z)
{
    edges.push_back((Edge){x,y,z});
    edges.push_back((Edge){y,x,z});
    G[x].push_back(edges.size()-2);
    G[y].push_back(edges.size()-1);
}

void dfs(int u,int f,int d)
{
    vis[u]=1;
    for(int i=0;i<G[u].size();i++)
    {
        Edge& e=edges[G[u][i]];
        int v=e.to,w=e.dist;
        if(v==f || vis[v])continue;
        fa[v][0]=u;
        maxcost[v][0]=w;
        deep[v]=d+1;
        dfs(v,u,d+1);
    }
}

void lca_init()
{
    for(int i=0;i<n*m;i++)for(int j=1;(1<<j)<n*m;j++)fa[i][j]=-1;
    for(int j=1;(1<<j)<n*m;j++)
        for(int i=0;i<n*m;i++)
            if(fa[i][j-1]!=-1)
            {
                int a=fa[i][j-1];
                fa[i][j]=fa[a][j-1];
                maxcost[i][j]=max(maxcost[i][j-1],maxcost[a][j-1]);
            }
}

int query(int p,int q)
{
    int log;
    if(deep[p]<deep[q])swap(p,q);
    for(log=1;(1<<log)<=deep[p];log++);
    log--;
    int ans=-(1<<30);
    for(int i=log;i>=0;i--)
        if(deep[p]-(1<<i)>=deep[q])
        {
            ans=max(ans,maxcost[p][i]);
            p=fa[p][i];
        }   
    if(p==q)return ans; //lca爲p或q
    for(int i=log;i>=0;i--)
        if(fa[p][i]!=-1 && fa[p][i]!=fa[q][i])
        {
            ans=max(ans,maxcost[p][i]);
            p=fa[p][i];
            ans=max(ans,maxcost[q][i]);
            q=fa[q][i];
        }
    ans=max(ans,maxcost[p][0]);
    ans=max(ans,maxcost[q][0]);
    return ans;//lca爲fa[p]或fa[q]
}

int main()
{
    ///freopen("input.in","r",stdin);
    cin>>n>>m>>q;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            scanf("%d",&a[i][j]),p[i*m+j]=i*m+j;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
        {
            if(i!=0)
            {
                cnt++;
                x[cnt]=i*m+j;y[cnt]=(i-1)*m+j;z[cnt]=max(a[i][j],a[i-1][j]);
            }
            if(i!=n-1)
            {
                cnt++;
                x[cnt]=i*m+j;y[cnt]=(i+1)*m+j;z[cnt]=max(a[i][j],a[i+1][j]);
            }
            if(j!=0)
            {
                cnt++;
                x[cnt]=i*m+j;y[cnt]=i*m+j-1;z[cnt]=max(a[i][j],a[i][j-1]);
            }
            if(j!=m-1)
            {
                cnt++;
                x[cnt]=i*m+j;y[cnt]=i*m+j+1;z[cnt]=max(a[i][j],a[i][j+1]);
            }
        }
    for(int i=1;i<=cnt;i++)e[i]=i;
    sort(e+1,e+1+cnt,cmp);
    for(int i=1;i<=cnt;i++)
    {
        int a=x[e[i]],b=y[e[i]],c=z[e[i]];
        int a2=findset(a),b2=findset(b);
        if(a2!=b2)
        {
            p[a2]=b2;
            AddEdge(a,b,c);
        }
    }
    deep[0]=0;
    fa[0][0]=-1;
    dfs(0,-1,0);
    lca_init();
    int x1,y1,x2,y2,u,v;
    while(q--)
    {
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        x1--;y1--;x2--;y2--;
        u=x1*m+y1;v=x2*m+y2;
        if(u==v)printf("%d\n",a[x1][y1]);
        else printf("%d\n",query(u,v));
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章