题解:
把每列的不同联通块看做一个点,相邻列若有共同的纵坐标有格子那么连边,这样会形成一棵树,且网格上两点的路径就是树上的一条路径。
然后就是点分治裸题,不过算距离比较麻烦。
注意到两点的路径最终在某一列的某一块停止,且进入的时候一定之前走的是最短距离(容易证明进入的点也是唯一的),那么这两点的距离等于两个最短距离加上进入的纵坐标绝对值差,即:
da+db+|ya−yb|
d
a
+
d
b
+
|
y
a
−
y
b
|
。
后面的绝对值是前缀最小值,维护两个树状数组即可。时间复杂度 O(nlog2n) O ( n log 2 n )
#include <bits/stdc++.h>
using namespace std;
typedef vector <int> Vec;
typedef set <int> Set;
typedef map <int,int> Map;
inline int rd() {
char ch=getchar(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=getchar();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=getchar();}
return i*f;
}
const int N=3e5+50,INF=0x3f3f3f3f;
int n,oc,tc;
Vec coors[N];
Vec oe[N];
Vec te[N];
Vec bit[N][2];
Map id[N];
int bl[N],ed[N],xd[N],bg[N],mx,total,G;
int yc[N][30],dis[N][30],sze[N],d[N],fa[N],vis[N];
inline void dfs(int x,int f) {
sze[x]=ed[x];
for(int e=te[x].size()-1;e>=0;e--) {
int v=te[x][e]; if(v==f||vis[v]) continue;
dfs(v,x); sze[x]+=sze[v];
}
}
inline void calcG(int x,int f) {
int mxv=total-sze[x];
for(int e=te[x].size()-1;e>=0;e--) {
int v=te[x][e]; if(v==f||vis[v]) continue;
calcG(v,x); mxv=max(mxv,sze[v]);
}
if(mxv<mx) G=x,mx=mxv;
}
queue <int> q;
inline void solve(int x,int f) {
fa[x]=f; d[x]=d[f]+1; vis[x]=1;
for(int i=1,o=id[xd[x]][coors[xd[x]][bg[x]]];i<=ed[x];++i,++o) {dis[o][d[x]]=0; yc[o][d[x]]=i; q.push(o);}
while(!q.empty()) {
int u=q.front(); q.pop();
for(int e=oe[u].size()-1;e>=0;e--) {
int v=oe[u][e]; if(vis[bl[v]] || yc[v][d[x]]) continue;
dis[v][d[x]]=dis[u][d[x]]+1;
yc[v][d[x]]=yc[u][d[x]];
q.push(v);
}
}
for(int i=0;i<=ed[x];++i) bit[x][0].push_back(INF), bit[x][1].push_back(INF);
for(int e=te[x].size()-1;e>=0;e--) {
int v=te[x][e]; if(vis[v]) continue;
dfs(v,x); mx=total=sze[v];
calcG(v,x); solve(G,x);
}
}
inline void inc(Vec &a,int p,int v) {for(int i=p;i<a.size();i+=(i&(-i))) a[i]=min(a[i],v);}
inline int ask(Vec &a,int p,int v=INF) {
for(int i=p;i;i-=(i&(-i))) v=min(v,a[i]);
return v;
}
inline void upt(int o) {
for(int j=bl[o];j;j=fa[j]) {
inc(bit[j][0],yc[o][d[j]],dis[o][d[j]]-yc[o][d[j]]);
inc(bit[j][1],ed[j]-yc[o][d[j]]+1,dis[o][d[j]]+yc[o][d[j]]);
}
}
inline int ask(int o) {
int ans=INF;
for(int j=bl[o];j;j=fa[j]) {
ans=min(ans,ask(bit[j][0],yc[o][d[j]])+dis[o][d[j]]+yc[o][d[j]]);
ans=min(ans,ask(bit[j][1],ed[j]-yc[o][d[j]]+1)+dis[o][d[j]]-yc[o][d[j]]);
}
return ans;
}
int main() {
n=rd();
for(int i=1;i<=n;i++) {
int x=rd(), y=rd();
coors[x].push_back(y);
}
for(int i=1;i<N;i++) {
if(!coors[i].size()) continue;
sort(coors[i].begin(),coors[i].end());
coors[i].erase(unique(coors[i].begin(),coors[i].end()),coors[i].end());
for(int p1=0,p2=0;p2<coors[i].size();++p2) {
int y=coors[i][p2]; id[i][y]=++oc;
if(p2&&coors[i][p2-1]+1==y) {oe[oc].push_back(oc-1); oe[oc-1].push_back(oc);}
else ++tc,bg[tc]=p2,xd[tc]=i;
bl[oc]=tc; ++ed[tc];
while(p1!=coors[i-1].size()&&coors[i-1][p1]<y) ++p1;
if(p1!=coors[i-1].size()&&coors[i-1][p1]==y) {
int o=id[i-1][y];
oe[o].push_back(oc); oe[oc].push_back(o);
te[bl[o]].push_back(tc); te[tc].push_back(bl[o]);
}
}
}
for(int i=1;i<=tc;i++) {
sort(te[i].begin(),te[i].end());
te[i].erase(unique(te[i].begin(),te[i].end()),te[i].end());
}
dfs(1,0); mx=total=sze[1];
calcG(1,0); solve(G,0);
for(int i=rd();i;i--) {
int op=rd(), x=rd(), y=rd(), o=id[x][y];
if(op==1) {
upt(o);
} else {
int t=ask(o);
printf("%d\n",(t<=n)?t:-1);
}
}
}