1. 程式人生 > >【BZOJ 4449】[Neerc2015]Distance on Triangulation 多邊形分治結構

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

-i 容易 uil oid mini type struct root 離線

這題好神啊……
正解方向是分治,據我所知的分治方法有:I.離線後直接對多邊形以及所有的詢問進行分治 II.建立多邊形的分治結構(對於三角形來說類似線段樹,對於對角線來說類似平衡樹),然後每次在這個分治結構上進行查詢 III.將原圖轉為其對偶圖(利用拓撲),發現是一棵樹,然後在這棵樹上進行分治(似乎也有離線分治和在線建立分治結構兩種方法)
我用的是第二種方法,感覺寫起來不是很容易,但是也並不惡心,具體實現以及具體問題的處理方法見代碼.
感覺這樣分治的復雜度是log的,實際證明最壞情況下存在使得任意一側的三角形數不少於n/3的分發,然而並不會證,大該感性理解一下吧.
思維筆記:I.分治無處不在 II.分治就是分治,也可以沒有信息的合並 III.分治的出發點也可以是砍半,就像二分一樣 IV.分治結構的建立類似分治,而分治結構的使用更像是二分

算法筆記:I.建立分治結構時所需信息,以及分治結構所需維護的信息,是不一樣的,分開考慮與處理會方便得多 II.在分治結構中,儲存信息的方式可以是對於每個點存儲其在每一層的信息,也可以是對於每一層存儲每個點的信息,兩者各有千秋,在這道題裏,個人感覺前者用起來更加方便 III.這道題分治的理由我感覺是——一個對角線把多邊形切成兩個部分,如果詢問的兩個點都在這兩個部分裏的其中一個裏面,那這次詢問一定與另一部分無關

#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; }

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