【WC2013】平面图(平面图转对偶图)(最小左转法)(扫描线点定位)(瓶颈路)

传送门


题解:

板子一大堆。

首先容易发现我们要求的就是对偶图的瓶颈路。

最小左转法转对偶图,询问离线,扫描线进行点定位,然后随便用你喜欢的方式求一下瓶颈路即可。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define db double
#define cs const

namespace IO{
	inline char gc(){
		static cs int Rlen=1<<22|1;static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++; 
	}template<typename T>T get(){
		char c;bool f=false;while(!isdigit(c=gc()))f=c=='-';
		T num=c^48;while(isdigit(c=gc()))num=((num+(num<<2))<<1)+(c^48);
		return f?-num:num;
	}inline int gi(){return get<int>();}
	inline db gd(){char c;bool f=false;
		while(!isdigit(c=gc()))f=c=='-';db x=c^48;
		while(isdigit(c=gc()))x=x*10+(c^48);
		if(c!='.')return f?-x:x;db y=1.;
		while(isdigit(c=gc()))x+=(y/=10)*(c^48);
		return f?-x:x;
	}char obuf[2000007],*oh=obuf;
	template<typename T>void print(T a,char c){
		static char ch[23];int tl=0;if(a<0)*oh++='-',a=-a;
		do ch[++tl]=a%10; while(a/=10);while(tl)*oh++=ch[tl--]^48;*oh++=c;
	}struct obuf_flusher{~obuf_flusher(){fwrite(obuf,1,oh-obuf,stdout);}}Flusher;
}using namespace IO;

using std::cerr;
using std::cout;

cs db eps=1e-12;
struct Pnt{
	db x,y;Pnt(){}Pnt(db _x,db _y):x(_x),y(_y){}
	friend Pnt operator+(cs Pnt &a,cs Pnt &b){return Pnt(a.x+b.x,a.y+b.y);}
	friend Pnt operator-(cs Pnt &a,cs Pnt &b){return Pnt(a.x-b.x,a.y-b.y);}
	friend db operator*(cs Pnt &a,cs Pnt &b){return a.x*b.y-a.y*b.x;}
	db len()cs{return x*x+y*y;}db ang()cs{return atan2(y,x);}
};

cs int N=1e5+7,M=N<<1|7;

int n,m,Q;

Pnt p[N*3];int tot;

int to[M],ec=1;db slope[M];
std::vector<int> E[N];int w[N];
inline void adde(int u,int v){
	E[u].push_back(++ec),to[ec]=v,slope[ec]=(p[v]-p[u]).ang();
	E[v].push_back(++ec),to[ec]=u,slope[ec]=(p[u]-p[v]).ang();
}
inline bool cmp_e(int i,int j){
	return slope[i]==slope[j]?to[i]<to[j]:slope[i]<slope[j];
}

int nxt[M],bel[M],ct,ban,ect;
struct Edge{int u,v,w;}edge[N];

int ps[M];

namespace Area{

void get_area(){
	for(int re i=1;i<=n;++i)
		std::sort(E[i].begin(),E[i].end(),cmp_e);
	for(int re u=1;u<=tot;++u)
		for(int re i=0;i<(int)E[u].size();++i){
			int j=(i==0)?(E[u].size()-1):(i-1);
			nxt[E[u][i]^1]=E[u][j];
		}
	for(int re i=2;i<=ec;++i){
		if(bel[i])continue;bel[i]=++ct;ll area=0;
		for(int re j=nxt[i];j!=i;j=nxt[j])
			area+=p[to[j^1]]*p[to[j]],bel[j]=ct;
		area+=p[to[i^1]]*p[to[i]];if(area<=0)ban=ct;
	}
}

}

namespace UnionSet{
	int fa[N];
	void init(int _n){for(int re i=1;i<=_n;++i)fa[i]=i;}
	int gf(int x){while(x!=fa[x])x=fa[x]=fa[fa[x]];return x;}
	void mg(int u,int v){fa[gf(u)]=gf(v);}
}
using UnionSet::gf;
using UnionSet::mg;

namespace Tree{

cs int N=1e5+7,M=N<<1|1;
int el[N],nxt[M],to[M],w[M],ec;
inline void adde(int u,int v,int vl){
	nxt[++ec]=el[u],el[u]=ec,to[ec]=v,w[ec]=vl;
	nxt[++ec]=el[v],el[v]=ec,to[ec]=u,w[ec]=vl;
}

int d[N],fa[N],top[N],vl[N],id[N],rt;
int siz[N],son[N],dfn[N],dfc;

void dfs1(int u,int p){
	fa[u]=p,d[u]=d[p]+1;id[u]=rt;
	for(int re e=el[u],v;e;e=nxt[e])
	if((v=to[e])!=p){
		dfs1(v,u);siz[u]+=siz[v];
		if(siz[v]>siz[son[u]])son[u]=v;
	}++siz[u];
}
void dfs2(int u,int tp){
	top[u]=tp,dfn[u]=++dfc;
	if(son[u])dfs2(son[u],tp);
	for(int re e=el[u],v;e;e=nxt[e])
		if((v=to[e])!=fa[u]&&v!=son[u])
			dfs2(v,v),vl[dfn[v]]=w[e];
		else if(v==son[u])vl[dfn[v]]=w[e];
}

namespace ST{
	int st[20][N],Log[N];
	void init(){
		for(int re i=2;i<=dfc;++i)Log[i]=Log[i>>1]+1;
		for(int re i=1;i<=dfc;++i)st[0][i]=vl[i];
		for(int re i=1;i<=Log[dfc];++i)
		for(int re j=1;j+(1<<i)-1<=dfc;++j)
		st[i][j]=std::max(st[i-1][j],st[i-1][j+(1<<(i-1))]);
	}
	inline int mx(int l,int r){
		int t=Log[r-l+1];
		return std::max(st[t][l],st[t][r-(1<<t)+1]);
	}
}

void init(){
	for(int re i=1;i<=ct;++i)
		if(!id[i])dfs1(rt=i,0),dfs2(i,i);
	ST::init();
}

inline int query(int u,int v){
	if(id[u]!=id[v]||!id[u]||id[u]==id[ban])return -1;
	int ans=0;while(top[u]!=top[v]){
		if(d[top[u]]>d[top[v]])std::swap(u,v);
		ans=std::max(ans,ST::mx(dfn[top[v]],dfn[v]));
		v=fa[top[v]];
	}if(u!=v){
		if(d[u]>d[v])std::swap(u,v);
		ans=std::max(ans,ST::mx(dfn[u]+1,dfn[v]));
	}return ans;
}

}

namespace ScanLine{

struct atom{int a,b,t,id;};
inline bool operator<(cs atom &a,cs atom &b){
	if(a.a==b.a)return a.t>b.t;
	if(p[a.a].x!=p[b.a].x)return p[a.a].x<p[b.a].x;
	return p[a.a].y>p[b.a].y;
}
struct  cmp_atom{
	bool operator()(cs atom &a,cs atom &b){
		if(a.a==a.b)return (p[b.b]-p[a.a])*(p[b.a]-p[a.a])<0;
		if(b.a==b.b)return (p[a.b]-p[b.a])*(p[a.a]-p[b.a])>0;
		db t1=(p[a.a]-p[b.b])*(p[a.b]-p[b.b]),t2=(p[a.a]-p[b.a])*(p[a.b]-p[b.a]);
		db t3=(p[b.a]-p[a.a])*(p[b.b]-p[a.a]),t4=(p[b.a]-p[a.b])*(p[b.b]-p[a.b]);
		return (t1<-eps&&t2<eps)||(t2<-eps&&t1<eps)||(t3>eps&&t4>-eps)||(t4>eps&&t3>-eps);
	}
};
std::set<atom,cmp_atom> S;
std::vector<atom> vec;

void get_area(){
	vec.clear();S.clear();
	for(int re i=1;i<=n;++i)
		for(int re e:E[i])
			if(p[to[e]].x>p[i].x){
				vec.push_back({i,to[e],0,e^1});
				vec.push_back({to[e],i,2,e^1});
			}
	for(int re i=0;i<Q;++i){
		p[++tot].x=gd(),p[tot].y=gd();
		vec.push_back({tot,tot,1,i<<1});
		p[++tot].x=gd(),p[tot].y=gd();
		vec.push_back({tot,tot,1,i<<1|1});
	}
	std::sort(vec.begin(),vec.end());
	for(auto &t:vec){
		switch(t.t){
			case 0:S.insert(t);break;
			case 2:S.erase(S.find({t.b,t.a,0,t.id}));break;
			case 1:{
				auto it=S.lower_bound(t);
				if(it==S.begin())continue;
				ps[t.id]=bel[(--it)->id];
			}
		}
	}
}

}

void Main(){
	n=gi(),m=gi();tot=n;
	for(int re i=1;i<=n;++i)p[i].x=gi(),p[i].y=gi();
	for(int re i=1;i<=m;++i){int u=gi(),v=gi();w[i]=gi();adde(u,v);}
	Area::get_area();UnionSet::init(ct);
	for(int re i=2;i<=ec;i+=2)
		if(bel[i]!=ban&&bel[i^1]!=ban)
			edge[++ect]={bel[i],bel[i^1],w[i>>1]};
	std::sort(edge+1,edge+ect+1,[](cs Edge &a,cs Edge &b){return a.w<b.w;});
	for(int re i=1;i<=ect;++i){
		int u=edge[i].u,v=edge[i].v;
		if(gf(u)==gf(v))continue;
		mg(u,v);Tree::adde(u,v,edge[i].w);
	}Tree::init();Q=gi();ScanLine::get_area();
	for(int re i=0;i<Q;++i)
		print(Tree::query(ps[i<<1],ps[i<<1|1]),'\n');
}

void file(){
#ifdef zxyoi
	freopen("plane.in","r",stdin);
#endif 
}
signed main(){file();Main();return 0;}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值