[主席树优化建图] LOJ#546. 「LibreOJ β Round #7」网格图

最简单的思路是离散化后 O(k2) O ( k 2 )

然而对于横着的朝向,极长的横着相连的格子的答案是相同的,竖着的同理

那么把极长的相连的格子也缩起来,用主席树优化建图,就可以 O(klogk) O ( k log ⁡ k ) 最短路了

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#define fi first
#define se second

using namespace std;

typedef pair<int,int> pii;

const int N=50010;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void read(int &x){
  char c=nc(); x=0;
  for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}

struct Line{
  int l,r,g;
  Line(){}
  Line(int _l,int _r,int _g):l(_l),r(_r),g(_g){}
  friend bool operator <(Line a,Line b){
    return a.l<b.l;
  }
};

int n,m,k,q,dis[N*200];
vector<int> h,s,hp[N<<2],sp[N<<2];
int x[N],y[N],sx,sy;
vector<Line> hl[N<<2],sl[N<<2];
vector<pii> ad[N<<2],de[N<<2];

int rt,ls[N*200],rs[N*200],ccnt;

int G[N*200],cnt;
struct edge{
  int t,nx,w;
}E[N*400];

inline void addedge(int x,int y,int w){
  //cerr<<'\t'<<x<<' '<<y<<' '<<w<<endl;
  E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt; E[cnt].w=w;
}

void add(int &g,int x,int l,int r,int y){
  int k=g; g=++ccnt; ls[g]=ls[k]; rs[g]=rs[k];
  if(l==r) return addedge(g,y,1);
  int mid=l+r>>1;
  if(x<=mid) add(ls[g],x,l,mid,y);
  else add(rs[g],x,mid+1,r,y);
  if(ls[g]) addedge(g,ls[g],0);
  if(rs[g]) addedge(g,rs[g],0);
}

void link(int g,int l,int r,int L,int R,int y){
  if(!g) return ;
  if(l==L && R==r){
    addedge(y,g,0); return ;
  }
  int mid=L+R>>1;
  if(r<=mid) link(ls[g],l,r,L,mid,y);
  else if(l>mid) link(rs[g],l,r,mid+1,R,y);
  else link(ls[g],l,mid,L,mid,y),link(rs[g],mid+1,r,mid+1,R,y);
}

queue<int> Q;
int vis[N*200];

int main(){
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
  read(n); read(m); read(k); read(q);
  for(int i=1;i<=k;i++){
    read(x[i]); read(y[i]);
    h.push_back(x[i]);
    if(x[i]>1) h.push_back(x[i]-1);
    if(x[i]<n) h.push_back(x[i]+1);
    s.push_back(y[i]);
    if(y[i]>1) s.push_back(y[i]-1);
    if(y[i]<m) s.push_back(y[i]+1);
  }
  read(sx); read(sy);
  h.push_back(sx); s.push_back(sy);
  if(sx>1) h.push_back(sx-1);
  if(sx<n) h.push_back(sx+1);
  if(sy>1) s.push_back(sy-1);
  if(sy<m) s.push_back(sy+1);
  h.push_back(n); s.push_back(m);
  sort(h.begin(),h.end()); sort(s.begin(),s.end());
  h.resize(unique(h.begin(),h.end())-h.begin());
  s.resize(unique(s.begin(),s.end())-s.begin());
  for(int i=1;i<=k;i++){
    x[i]=lower_bound(h.begin(),h.end(),x[i])-h.begin();
    y[i]=lower_bound(s.begin(),s.end(),y[i])-s.begin();
    hp[x[i]].push_back(y[i]);
    sp[y[i]].push_back(x[i]);
  }
  n=lower_bound(h.begin(),h.end(),n)-h.begin();
  m=lower_bound(s.begin(),s.end(),m)-s.begin();
  for(int i=0;i<h.size();i++){
    sort(hp[i].begin(),hp[i].end());
    int lst=-1;
    for(int j=0;j<hp[i].size();j++){
      if(lst+1<hp[i][j]) hl[i].push_back(Line(lst+1,hp[i][j]-1,++ccnt));
      lst=hp[i][j];
    }
    if(lst+1<=m) hl[i].push_back(Line(lst+1,m,++ccnt));
  }
  for(int i=0;i<s.size();i++){
    sort(sp[i].begin(),sp[i].end());
    int lst=-1;
    for(int j=0;j<sp[i].size();j++){
      if(lst+1<sp[i][j]) sl[i].push_back(Line(lst+1,sp[i][j]-1,++ccnt));
      lst=sp[i][j];
    }
    if(lst+1<=n) sl[i].push_back(Line(lst+1,n,++ccnt));
  }
  for(int i=0;i<s.size();i++){
    for(int j=0;j<sl[i].size();j++)
      ad[sl[i][j].l].push_back(pii(i,sl[i][j].g));
  }
  for(int i=0;i<h.size();i++){
    for(int j=0;j<ad[i].size();j++)
      add(rt,ad[i][j].fi,0,s.size()-1,ad[i][j].se);
    for(int j=0;j<hl[i].size();j++)
      link(rt,hl[i][j].l,hl[i][j].r,0,s.size()-1,hl[i][j].g);
    ad[i].clear();
  }
  rt=0;
  for(int i=0;i<h.size();i++)
    for(int j=0;j<hl[i].size();j++)
      ad[hl[i][j].l].push_back(pii(i,hl[i][j].g));
  for(int i=0;i<s.size();i++){
    for(int j=0;j<ad[i].size();j++)
      add(rt,ad[i][j].fi,0,h.size()-1,ad[i][j].se);
    for(int j=0;j<sl[i].size();j++)
      link(rt,sl[i][j].l,sl[i][j].r,0,h.size()-1,sl[i][j].g);
  }
  sx=lower_bound(h.begin(),h.end(),sx)-h.begin();
  sy=lower_bound(s.begin(),s.end(),sy)-s.begin();
  int S1=hl[sx][upper_bound(hl[sx].begin(),hl[sx].end(),Line(sy,0,0))-hl[sx].begin()-1].g;
  int S2=sl[sy][upper_bound(sl[sy].begin(),sl[sy].end(),Line(sx,0,0))-sl[sy].begin()-1].g;
  for(int i=1;i<=ccnt;i++) dis[i]=1<<29;
  dis[S1]=dis[S2]=0; Q.push(S1); Q.push(S2); vis[S1]=vis[S2]=1;
  while(!Q.empty()){
    int x=Q.front(); Q.pop(); vis[x]=0;
    for(int i=G[x];i;i=E[i].nx)
      if(dis[E[i].t]>dis[x]+E[i].w){
    dis[E[i].t]=dis[x]+E[i].w;
    if(!vis[E[i].t])
      vis[E[i].t]=1,Q.push(E[i].t);
      }
  }
  while(q--){
    int x,y; read(x); read(y);
    x=lower_bound(h.begin(),h.end(),x)-h.begin();
    y=lower_bound(s.begin(),s.end(),y)-s.begin();
    int T1=upper_bound(hl[x].begin(),hl[x].end(),Line(y,0,0))-hl[x].begin()-1;
    int T2=upper_bound(sl[y].begin(),sl[y].end(),Line(x,0,0))-sl[y].begin()-1;
    T1=hl[x][T1].g; T2=sl[y][T2].g;
    int ans=min(dis[T1],dis[T2]);
    if(ans==(1<<29)) ans=-1;
    printf("%d\n",ans);
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值