P14645 [POI 2025/2026 #1] 传话 / Dostawy

思路

首先我们一定将先招募的英雄派遣至更远的堡垒。
每个英雄在出发后一定互不干扰,且走的是到达目的地的最短路。

证明

假设会在某点相遇,导致某个英雄无法继续行走。
先出发的在到达前会一直在行进的路上,先到达相遇点。
若其后到达或与另一名同时到达,则一定不是走的最短路线,不成立。
在其到达终点后,若另一名继续行进,被其阻挡,则另一名要么走的不是最短路,要么路径更远,均不符合要求。
故假设不成立,得证。

然后障碍的数量不会增多,位置也不会改变,所以不管某位置上是不是堡垒,从出发点到它的所需时间都不会变。
这个时间我们可以用 bfs 求,最劣 $O(n^2)$。
然后因为英雄们互不干扰,所以我们可以把问题转化为一维的。
设所有所需时间从大到小排序后的数组为 $dis$,共有 $cnt$ 个。
则最开始出发的会在 $dis_{cnt}$ 时间内走完,而每晚出发的一位,其所用时间都会是 $dis_i+(cnt-i)$。
那么我们对这个东西求 $\max$ 就是最终答案。
但是线性仍然不够优秀,所以考虑用权值线段树优化。
思路也很简单,维护每个值分别有多少个和比它大的有多少个即可。
注意这个值所需的时间要按照最后出发的一个算。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include<bits/stdc++.h>
#define fir first
#define sec second
#define int long long
#define pii pair<int,int>
#define fep(i,s,e) for(int i=s;i<e;i++)
#define pef(i,s,e) for(int i=s;i>e;i--)
#define rep(i,s,e) for(int i=s;i<=e;i++)
#define per(i,s,e) for(int i=s;i>=e;i--)
namespace FastIO{
template<typename T>inline void read(T &x){
x=0;int f=1;char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+(c^48);x*=f;
}
template<typename T,typename...Args>
inline void read(T &x,Args&...args){
read(x);
read(args...);
}
template<typename T>void print(T x){
if(x<0)x=-x,putchar('-');
if(x>9)print(x/10);
putchar((x%10)^48);
}
}
using namespace std;
using namespace FastIO;
const int N=1007;
const int inf=1e18;
int n,q,a[N][N],dis[N][N];
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
void bfs(){
queue<pii>q;
rep(i,1,n)rep(j,1,n)dis[i][j]=inf;
dis[1][1]=0;
q.push({1,1});
while(q.size()){
int x=q.front().fir,y=q.front().sec;q.pop();
fep(i,0,4){
int nx=x+dx[i],ny=y+dy[i];
if(nx<1||ny<1||nx>n||ny>n)continue;
if(a[nx][ny]==-1)continue;
if(dis[nx][ny]>dis[x][y]+1){
dis[nx][ny]=dis[x][y]+1;
q.push({nx,ny});
}
}
}
}
struct node{
int c;
int mx;
};
struct segment_tree{
node s[4*N*N];
void pushup(int p){
s[p].c=s[p*2].c+s[p*2+1].c;
s[p].mx=max(s[p*2].mx+s[p*2+1].c,s[p*2+1].mx);
}
void build(int p,int l,int r){
if(l==r){
s[p].c=0;
s[p].mx=-inf;
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
pushup(p);
}
void update(int p,int l,int r,int x,int k){
if(l==r){
s[p].c+=k;
if(s[p].c==0)s[p].mx=-inf;
else s[p].mx=x+s[p].c-1;
return;
}
int mid=(l+r)>>1;
if(x<=mid)update(p*2,l,mid,x,k);
else update(p*2+1,mid+1,r,x,k);
pushup(p);
}
}G;
signed main(){
read(n,q);
rep(i,1,n){
rep(j,1,n){
char c;cin>>c;
if(c=='#')a[i][j]=-1;
else if(c=='F')a[i][j]=1;
else a[i][j]=0;
}
}
bfs();
G.build(1,0,n*n);
rep(i,1,n){
rep(j,1,n){
if(a[i][j]==1&&dis[i][j]!=inf){
G.update(1,0,n*n,dis[i][j],1);
}
}
}
while(q--){
int x,y;
read(x,y);
if(G.s[1].mx<0)puts("0");
else{
print(G.s[1].mx);
putchar('\n');
}
if(a[x][y]==1){
a[x][y]=0;
if(dis[x][y]!=inf)G.update(1,0,n*n,dis[x][y],-1);
}
else if(a[x][y]==0){
a[x][y]=1;
if(dis[x][y]!=inf)G.update(1,0,n*n,dis[x][y],1);
}
}
if(G.s[1].mx<0)print(0);
else print(G.s[1].mx);
}