zoukankan      html  css  js  c++  java
  • 【BZOJ4449】[Neerc2015] Distance on Triangulation(分治+BFS)

    点此看题面

    大致题意: 给定一个多边形以及一组三角剖分,每条边边权为(1),每次询问两点间最短路。

    前言

    写得心态爆炸当场去世。。。

    推荐还是去写点分治吧(虽然我并不知道怎么写),我这种做法要出人命的。。。

    大致想法

    有一道和这题非常相似的题目:【BZOJ4456】[ZJOI2016] 旅行者

    我们可以和上面这题一样,采用分治的做法,每次选择中间的剖分边,把多边形分成两部分。(具体思路可以直接参考上面那道题)

    这题唯一一个比较好的地方,就是因为边权都是(1),可以直接(BFS),而不用写最短路。

    但是,这道题和上面那题比起来,真的麻烦了很多。

    要注意,此题多边形被分成两部分,不光要把询问分成两部分,还要把多边形的点以及剖分边也给分成两部分,于是一下多了很多细节。

    具体的细节还是详见代码吧。

    代码

    #pragma GCC optimize(2)
    #pragma GCC optimize("inline") 
    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 50000
    #define Q 100000
    #define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
    #define Gmin(x,y) (x>(y)&&(x=(y)))
    #define Swap(x,y) (x^=y^=x^=y)
    #define pb push_back
    using namespace std;
    int n,Qt,In[N+5],ee,lnk[N+5],que[N+5],dis[N+5];struct edge {int to,nxt;}e[4*N+5];
    struct S {int x,y;I bool operator < (Con S& o) Con {return x^o.x?x<o.x:y>o.y;}}s[N+5];
    int p[N+5],ans[Q+5];struct Qry {int p,x,y;}q[Q+5],ql[Q+5],qr[Q+5];S sl[N+5],sr[N+5];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define pc(c) (C==E&&(clear(),0),*C++=c)
    		#define D isdigit(c=tc())
    		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
    	public:
    		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
    		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    		Tp I void writeln(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);pc('
    ');}
    		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
    }F;
    I void BFS(CI s,Con vector<int>& v)//BFS求最短路
    {
    	static int ti=0;RI i,sz,k,H=1,T=1;++ti;
    	for(i=0,sz=v.size();i^sz;++i) In[v[i]]=ti,dis[v[i]]=-1;dis[que[1]=s]=0;
    	W(H<=T) for(i=lnk[k=que[H++]];i;i=e[i].nxt)
    		!~dis[e[i].to]&&In[e[i].to]==ti&&(dis[que[++T]=e[i].to]=dis[k]+1);
    }
    I int find(CI p,CI x,CI y)//二分一条剖分线一侧的剖分边数
    {
    	RI l,r,mid,t1,t2;
    	l=x,r=p-1;W(l<r) s[mid=l+r+1>>1]<s[p]?l=mid:r=mid-1;t1=l;//找到左边左侧的剖分边
    	l=p-1,r=y;W(l<r) s[mid=l+r-1>>1].x>=s[p].y?r=mid:l=mid+1;t2=r;//找到右边左侧的剖分边
    	return (t1-x+1)+(y-t2+1);//返回答案
    }
    vector<int> v[50];I void Solve(CI x,CI y,CI d,CI L,CI R)//分治
    {
    	RI i,sz=v[d].size(),wl=0,wr=0,tl=0,tr=0;vector<int> vl,vr;
    	if(x>y||!sz||L>R) return;RI mid=x,X,Y;p[x]=find(x,x,y);//判边界
    	#define Calc(id) max(p[id],y-x+1-p[id])
    	for(i=x+1;i<=y;++i) p[i]=find(i,x,y),Calc(i)<Calc(mid)&&(mid=i);//找到中间的剖分边
    	for(BFS(X=s[mid].x,v[d]),i=L;i<=R;++i) Gmin(ans[q[i].p],dis[q[i].x]+dis[q[i].y]);//最短路更新答案
    	for(BFS(Y=s[mid].y,v[d]),i=L;i<=R;++i) Gmin(ans[q[i].p],dis[q[i].x]+dis[q[i].y]);//最短路更新答案
    	for(i=x;i<=y;++i) i^mid&&(((s[i].x<X||s[i].y>Y)?sl[++wl]:sr[++wr])=s[i],0);//分边
    	for(i=1;i<=wl;++i) s[x+i-1]=sl[i];for(i=1;i<=wr;++i) s[x+wl+i-1]=sr[i];//放回原数组
    	for(i=L;i<=R;++i)//分询问
    		(q[i].x<X||q[i].x>Y)&&(q[i].y<X||q[i].y>Y)&&(ql[++tl]=q[i],0),
    		q[i].x>=X&&q[i].x<=Y&&q[i].y>=X&&q[i].y<=Y&&(qr[++tr]=q[i],0);
    	for(i=1;i<=tl;++i) q[L+i-1]=ql[i];for(i=1;i<=tr;++i) q[L+tl+i-1]=qr[i];//放回原数组
    	for(i=0;i^sz;++i) (v[d][i]<=X||v[d][i]>=Y)&&(v[d+1].pb(v[d][i]),0);//找出左侧点
    	Solve(x,x+wl-1,d+1,L,L+tl-1),vector<int>().swap(v[d+1]);//注意剖分边上的点要放入两边,因此得开vector
    	for(i=0;i^sz;++i) v[d][i]>=X&&v[d][i]<=Y&&(v[d+1].pb(v[d][i]),0);//找出右侧点
    	Solve(x+wl,y-1,d+1,L+tl,L+tl+tr-1),vector<int>().swap(v[d+1]);
    }
    int main()
    {
    	RI i;for(F.read(n),i=1;i^n;++i) add(i,i+1),add(i+1,i);add(n,1),add(1,n);//连边
    	for(i=1;i<=n-3;++i) F.read(s[i].x,s[i].y),add(s[i].x,s[i].y),add(s[i].y,s[i].x);
    	for(i=1;i<=n-3;++i) s[i].x>s[i].y&&Swap(s[i].x,s[i].y);sort(s+1,s+n-2);//给剖分边排序
    	for(F.read(Qt),i=1;i<=Qt;++i) F.read(q[i].x,q[i].y),ans[q[i].p=i]=q[i].x^q[i].y?n:0;
    	for(i=1;i<=n;++i) v[0].pb(i);Solve(1,n-3,0,1,Qt);
    	for(i=1;i<=Qt;++i) F.writeln(ans[i]);return F.clear(),0;
    }
    
  • 相关阅读:
    python学习笔记 async and await
    python学习笔记 异步asyncio
    python学习笔记 协程
    python学记笔记 2 异步IO
    python学习笔记 可变参数关键字参数**kw相关学习
    逆波兰表达式 栈表达式计算
    Codeforces 270E Flawed Flow 网络流问题
    Codeforces 219D Choosing Capital for Treeland 2次DP
    kuangbin 带你飞 概率期望
    函数式编程思想:以函数的方式思考,第3部分
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ4449.html
Copyright © 2011-2022 走看看