【BZOJ 4449】[Neerc2015]Distance on Triangulation 多邊形分治結構

這題好神啊……
正解方向是分治,據我所知的分治方法有:I.離線後直接對多邊形以及全部的詢問進行分治 II.創建多邊形的分治結構(對於三角形來講相似線段樹,對於對角線來講相似平衡樹),而後每次在這個分治結構上進行查詢 III.將原圖轉爲其對偶圖(利用拓撲),發現是一棵樹,而後在這棵樹上進行分治(彷佛也有離線分治和在線創建分治結構兩種方法)
我用的是第二種方法,感受寫起來不是很容易,可是也並不噁心,具體實現以及具體問題的處理方法見代碼.
感受這樣分治的複雜度是log的,實際證實最壞狀況下存在使得任意一側的三角形數很多於n/3的分發,然而並不會證,大該感性理解一下吧.
思惟筆記:I.分治無處不在 II.分治就是分治,也能夠沒有信息的合併 III.分治的出發點也能夠是砍半,就像二分同樣 IV.分治結構的創建相似分治,而分治結構的使用更像是二分
算法筆記:I.創建分治結構時所需信息,以及分治結構所需維護的信息,是不同的,分開考慮與處理會方便得多 II.在分治結構中,儲存信息的方式能夠是對於每一個點存儲其在每一層的信息,也能夠是對於每一層存儲每一個點的信息,二者各有千秋,在這道題裏,我的感受前者用起來更加方便 III.這道題分治的理由我感受是——一個對角線把多邊形切成兩個部分,若是詢問的兩個點都在這兩個部分裏的其中一個裏面,那此次詢問必定與另外一部分無關html

#pragma GCC optimize("O3")
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define pb push_back
#define ft first
#define sd second
#define mmp(a,b) (std::make_pair(a,b))
char xB[(1<<15)+10],*xS,*xT;
#define gtc (xS==xT&&(xT=((xS=xB)+fread(xB,1,1<<15,stdin)),xS==xT)?0:*xS++)
inline void read(int &x){
  register char ch=gtc;
  for(x=0;ch<'0'||ch>'9';ch=gtc);
  for(;ch>='0'&&ch<='9';x=(x<<1)+(x<<3)+ch-'0',ch=gtc);
}
typedef std::pair<int,int> pii;
typedef std::vector<int> vi;
typedef std::vector<pii> vii;
const int A=30,N=52000,Inf=0x3f3f3f3f;
vi tmp1;
vii tmp2;
struct Block{
  Block *ch[2];
  pii cut;
}*root,block[N<<2];
#define newblock (block+(sz++))
int to[N][A],dis[N][A][2];
int q[N],front,back,vis[N],id[N];
int n;
struct V{int to,next;}c[N<<2];
int head[N],t;
inline void add(int x,int y){
  c[++t].to=y,c[t].next=head[x],head[x]=t;
  c[++t].to=x,c[t].next=head[y],head[y]=t;
}
int sz,cnt;
inline void bfs(int S,int deep,int opt){
  ++cnt,front=back=0,q[back++]=S;
  dis[S][deep][opt]=0,vis[S]=cnt;
  register int x,i;
  while(front!=back){
    x=q[front++];
    for(i=head[x];i;i=c[i].next)
      if(vis[c[i].to]!=cnt){
        vis[c[i].to]=cnt;
        dis[c[i].to][deep][opt]=dis[x][deep][opt]+1;
        q[back++]=c[i].to;
      }
  }
}
inline void build(Block *&p,register vi poi,register vii cut,int deep){
  p=newblock;
  if(cut.size()==0)return;
  pii mini;
  int min=Inf,temp,size1=poi.size(),size2=cut.size();
  register int i;
  for(i=0;i<size2;++i){
    temp=std::abs(id[cut[i].ft]-id[cut[i].sd])+1;
    temp=std::max(temp,size1-temp+2);
    if(temp<min)
      min=temp,mini=cut[i];
  }
  p->cut=mini;
  int l=id[mini.ft],r=id[mini.sd];
  if(l>r)std::swap(l,r);
  tmp1.clear(),tmp2.clear();
  for(i=0;i<=l;++i){
    tmp1.pb(poi[i]);
    id[poi[i]]=tmp1.size()-1;
    to[poi[i]][deep]=1;
  }
  for(i=r;i<size1;++i){
    tmp1.pb(poi[i]);
    id[poi[i]]=tmp1.size()-1;
    to[poi[i]][deep]=1;
  }
  for(i=0;i<size2;++i){
    if(cut[i]==mini)continue;
    if(to[cut[i].ft][deep]==1&&to[cut[i].sd][deep]==1)
      tmp2.pb(cut[i]);
  }
  build(p->ch[1],tmp1,tmp2,deep+1);
  tmp1.clear(),tmp2.clear();
  for(i=l;i<=r;++i){
    tmp1.pb(poi[i]);
    id[poi[i]]=i-l;
    to[poi[i]][deep]=0;
  }
  for(i=0;i<size2;++i){
    if(cut[i]==mini)continue;
    if(to[cut[i].ft][deep]==0&&to[cut[i].sd][deep]==0)
      tmp2.pb(cut[i]);
  }
  build(p->ch[0],tmp1,tmp2,deep+1);
  for(i=0;i<size1;++i)head[poi[i]]=0;
  t=0;
  for(i=1;i<size1;++i)
    add(poi[i],poi[i-1]);
  add(poi[size1-1],poi[0]);
  for(i=0;i<size2;++i)
    add(cut[i].ft,cut[i].sd);
  bfs(mini.ft,deep,0);
  bfs(mini.sd,deep,1);
}
inline int query(Block *p,int x,int y,int deep){
  if(!p->ch[0])return 1;
  if(p->cut.ft==x)return dis[y][deep][0];
  if(p->cut.sd==x)return dis[y][deep][1];
  if(p->cut.ft==y)return dis[x][deep][0];
  if(p->cut.sd==y)return dis[x][deep][1];
  if(to[x][deep]==to[y][deep])return query(p->ch[to[x][deep]],x,y,deep+1);
  int ret=dis[x][deep][0]+dis[y][deep][0];
  ret=std::min(ret,dis[x][deep][1]+dis[y][deep][1]);
  return ret;
}
int main(){
  read(n);
  register int i;pii rio;
  for(i=1;i<=n;++i)
    tmp1.pb(i),id[i]=i-1;
  for(i=1;i<=n-3;++i)
    read(rio.ft),read(rio.sd),tmp2.pb(rio);
  build(root,tmp1,tmp2,1);
  int T,x,y;
  read(T);
  while(T--){
    read(x),read(y);
    printf("%d\n",x==y?0:query(root,x,y,1));
  }
  return 0;
}
相關文章
相關標籤/搜索