2018徐州网络赛 J. Maze Designer

大水题:  竟然TMD 没有看到这个题,  CCCCC

代码:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N =250005;

int rmq[N*2];

struct ST
{
    int mm[N*2];
    int anc[2*N][20];
    void init(int n)
    {
        mm[0]=-1;
        for(int i=1;i<=n;i++){
            mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
            anc[i][0]=i;
        }
        for(int j=1;j<=mm[n];j++){
            for(int i=1;i+(1<<j)-1<=n;i++){
                anc[i][j]=rmq[anc[i][j-1]] < rmq[anc[i+(1<<(j-1))][j-1]]?anc[i][j-1]:anc[i+(1<<(j-1))][j-1];
            }
        }
    }

    int query(int a,int b)
    {
        if(a>b) swap(a,b);
        int k=mm[b-a+1];
        return rmq[anc[a][k]] <= rmq[anc[b-(1<<k)+1][k]]?anc[a][k]:anc[b-(1<<k)+1][k];
    }
};

struct node
{
    int v,next;
}edge[N*2];

int tot,head[N];
int dfns[N*2]; ///  欧拉序列,也就是dfs序,  长度为2*n-1, 下标从1 开始.
int pp[N];  /// pp[i] 表示在dfns 中第一次出现的位置
//int L[N],R[N]; /// 表示当前节点dfs序中管辖的区间看情况使用
int cnt;
int clo; /// 时钟标记 用于L,R
ST st;

void init()
{
    tot=clo=cnt=0;
    memset(head,-1,sizeof(head));
}

void add(int u,int v)
{
    edge[++tot].v=v; edge[tot].next=head[u]; head[u]=tot;
}

void dfs(int u,int fa,int deep)
{
    dfns[++cnt]=u; rmq[cnt]=deep; pp[u]=cnt;
   // L[u]=++clo;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==fa) continue;
        dfs(v,u,deep+1);
        dfns[++cnt]=u;
        rmq[cnt]=deep;
    }
    //R[u]=clo;
}

void LCA_init(int rt,int node_num)
{
    cnt=0;
    dfs(rt,rt,0);
    st.init(2*node_num-1);
}

int LCA(int u,int v)
{
    return dfns[st.query(pp[u],pp[v])];
}

struct yjt
{
    ll d;
    ll r;
}mp[505][505];

struct eee
{
    int u,v;
    int f;
    ll w;
}Edge[N*4];
int tot1;

int f[N];
int n,m;
char s[5];
int dep[N];

void build(int x1,int y1,int x2,int y2,ll val)
{
    int id1=(x1-1)*m+y1;
    int id2=(x2-1)*m+y2;
    Edge[++tot1].u=id1;
    Edge[tot1].v=id2;
    Edge[tot1].w=val;
    Edge[tot1].f=0;
    Edge[++tot1].u=id2;
    Edge[tot1].v=id1;
    Edge[tot1].w=val;
    Edge[tot1].f=0;
}

bool cmp(eee a,eee b)
{
    return a.w>b.w;
}

int getf(int x)
{
    return f[x]==x?x:(f[x]=getf(f[x]));
}

int merge(int u,int v)
{
    int t1=getf(u);
    int t2=getf(v);
    if(t1!=t2){
        f[t2]=t1;
        return 1;
    }
    return 0;
}

void zuidashengchengshu()
{

    sort(Edge+1,Edge+tot1+1,cmp);
    for(int i=0;i<=n*m+2;i++) f[i]=i;
    int cnt=0;
    for(int i=1;i<=tot1;i++){
        int u=Edge[i].u;
        int v=Edge[i].v;
        if(merge(u,v)){
            cnt++;
            Edge[i].f=1;
            if(cnt==n*m-1) break;
        }
    }
    init();
    for(int i=1;i<=tot1;i++){
        if(Edge[i].f){
            add(Edge[i].u,Edge[i].v);
            add(Edge[i].v,Edge[i].u);
        }
    }
    LCA_init(1,n*m);

}

int main()
{
    int x1,y1,x2,y2;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%s %lld %s %lld",s,&mp[i][j].d,s,&mp[i][j].r);
        }
    }

    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(i==n){
                if(j==m) continue;
                build(i,j,i,j+1,mp[i][j].r);
            }
            else{
                if(j==m){
                    build(i,j,i+1,j,mp[i][j].d);
                }
                else{
                    build(i,j,i+1,j,mp[i][j].d);
                    build(i,j,i,j+1,mp[i][j].r);
                }
            }
        }
    }

    zuidashengchengshu();
    for(int i=1;i<=2*(n*m)-1;i++){
        dep[dfns[i]]=rmq[i];
    }

    int Q;
    scanf("%d",&Q);
    while(Q--)
    {
        scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
        int id1=(x1-1)*m+y1;
        int id2=(x2-1)*m+y2;
        int lca=LCA(id1,id2);
        int Ans=dep[id1]-dep[lca]+dep[id2]-dep[lca];
        printf("%d\n",Ans);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值