专栏文章

AT_abc429_f

AT_abc429_f题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minhylju
此快照首次捕获于
2025/12/02 02:43
3 个月前
此快照最后确认于
2025/12/02 02:43
3 个月前
查看原文

思路

感觉这题和 这题 是很像的,虽然那题我没有通过。
注意到如果只有三行,则不存在在中间绕路的情况。
所以考虑线段树,维护两列之间所有的位置答案。
对于每一个节点,不关心中间移动的具体过程,记 wi,jw_{i,j} 表示从最左边的第 ii 行到最右边的第 jj 行的最小步数,不可达记为无穷大。
合并显然有 333^3 的合并方法。
总复杂度 O(NlogN)O(N\log N),带一个 2727 倍左右的常数。

代码

CPP
#include<bits/stdc++.h>
using namespace std;
const int N=200005;
int w[8*N][3][3];
char a[3][N];
void pushup(int u)
{
    int x=u<<1,y=u<<1|1;
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
        {
            w[u][i][j]=1e9;
            for(int k=0;k<3;k++)
                w[u][i][j]=min(w[u][i][j],
                    w[x][i][k]+w[y][k][j]+1);
        }
}
void build(int u,int l,int r)
{
    if(l==r)
    {
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)//初始化节点状态
            {
                bool flag=1;
                for(int k=min(i,j);k<=max(i,j);k++)
                    if(a[k][l]=='#')flag=0;
                if(flag)w[u][i][j]=abs(i-j);
                else w[u][i][j]=1e9;
            }
        return;
    }
    int mid=(l+r)>>1;
    build(u<<1,l,mid);
    build(u<<1|1,mid+1,r);
    pushup(u);
}
void to(int u,int l,int r,int x,int t)
{
    if(l==r)
    {
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)//复制 build 里的代码
            {
                bool flag=1;
                for(int k=min(i,j);k<=max(i,j);k++)
                    if(a[k][l]=='#')flag=0;
                if(flag)w[u][i][j]=abs(i-j);
                else w[u][i][j]=1e9;
            }
        return;
    }
    int mid=(l+r)>>1;
    if(mid>=x)to(u<<1,l,mid,x,t);
    else to(u<<1|1,mid+1,r,x,t);
    pushup(u);
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int n,T;
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[0][i];
    for(int i=1;i<=n;i++)cin>>a[1][i];
    for(int i=1;i<=n;i++)cin>>a[2][i];
    build(1,1,n);cin>>T;
    while(T--)
    {
        int x,y;
        cin>>x>>y;x--;
        if(a[x][y]=='#')a[x][y]='.';
        else a[x][y]='#';
        to(1,1,n,y,x);
        cout<<(w[1][0][2]==1e9?-1:w[1][0][2])<<'\n';
    }
    return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...