把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P6976 [NEERC2015]Distance on Triangulation

题面传送门
容易发现三角剖分一定是一个平面图。因此所有边除了在端点不交。
如果我们有一条边,并把这两个点及其相邻的边删去,则会分成两个联通块。如果一个询问的两端点分别在这两个联通块内,则这两个点之间的最短路一定会经过这条边两个端点中的一个。于是我们有了一个类似于分治的思想:每次选取一条边,跑出两个端点到当前联通块之间的答案,并处理当前在这个联通块内的询问。
如果我们每次选取的边都均分了这个联通块,则复杂度为\(O((n+q)\log n)\)可以接受。
问题在于选出这条边,我们一定是尽量想要选出分成的两部分最小值最大的边,这样子如果不是三角剖分实际上可以卡掉,但是三角剖分对偶后发现这个东西就是点分治的重心因此复杂度是正确的是\(O((n+q)\log n)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (100000+5)
#define M ((N<<2)+5)
#define K (350)
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((k+1)*(x)+(y))
#define R(n) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;vector<int> F[N];
int op[N],x,y,n,m,Sh,Ans[N],D1[N],D2[N];queue<int> Q;vector<int> Id;
struct Edge{int x,y;};vector<Edge>S;I bool cmp(Edge x,Edge y){return x.x^y.x?x.x<y.x:x.y<y.y;}struct Ques{int x,y,id;};vector<Ques> G;
namespace Tree{
	int F[N];I void Ins(int x,int y){while(x<=n) F[x]+=y,x+=x&-x;}I int Qry(int x){int Ans=0;while(x) Ans+=F[x],x-=x&-x;return Ans;}
}
I void Solve(vector<Edge> S,vector<Ques> G,vector<int> Id){
	if(G.empty()||S.empty()) return;int Ps=-1,x;Edge Ns;for(int i:Id) Tree::Ins(i,1);for(Edge i:S) x=Tree::Qry(i.y)-Tree::Qry(i.x-1),x=min(x,Id.size()-x),x>Ps&&(Ns=i,Ps=x);
	for(int i:Id) Tree::Ins(i,-1),F[i].clear();for(Edge i:S) F[i.x].PB(i.y),F[i.y].PB(i.x);//if(S.size()>1000)cerr<<S.size()<<' '<<G.size()<<' '<<Id.size()<<' '<<Ps<<'\n';
	for(int i:Id) D1[i]=D2[i]=1e9,op[i]=0;D1[Ns.x]=D2[Ns.y]=0;
	Q.push(Ns.x);while(!Q.empty()) {x=Q.front();Q.pop();for(int i:F[x]) D1[i]>D1[x]+1&&(Q.push(i),D1[i]=D1[x]+1);}
	Q.push(Ns.y);while(!Q.empty()) {x=Q.front();Q.pop();for(int i:F[x]) D2[i]>D2[x]+1&&(Q.push(i),D2[i]=D2[x]+1);}
	vector<int> I1,I2;vector<Edge> S1,S2;vector<Ques> G1,G2;I1.clear();I2.clear();S1.clear();S2.clear();G1.clear();G2.clear();
	for(Ques i:G) Ans[i.id]=min(min(min(D1[i.x]+D1[i.y],D2[i.x]+D2[i.y]),min(D1[i.x]+D2[i.y]+1,D1[i.y]+D2[i.x]+1)),Ans[i.id]);
	for(int i:Id) if(i>=Ns.x&&i<=Ns.y) op[i]=1,I1.PB(i);for(Ques i:G) op[i.x]==op[i.y]&&op[i.x]&&(G1.PB(i),0);for(Edge i:S) (i.x^Ns.x||i.y^Ns.y)&&op[i.x]==op[i.y]&&op[i.x]&&(S1.PB(i),0);
	for(int i:Id) if(i<=Ns.x||i>=Ns.y) op[i]=-1,I2.PB(i);for(Ques i:G) op[i.x]==op[i.y]&&op[i.x]==-1&&(G2.PB(i),0);for(Edge i:S) (i.x^Ns.x||i.y^Ns.y)&&op[i.x]==op[i.y]&&op[i.x]==-1&&(S2.PB(i),0);
	Solve(S1,G1,I1);Solve(S2,G2,I2);
} 
int main(){
	freopen("1.in","r",stdin);//freopen("karen.out","w",stdout);
	int i,j;scanf("%d",&n);for(i=1;i<=n;i++) S.PB((Edge){i,i%n+1});for(i=1;i<=n-3;i++) scanf("%d%d",&x,&y),S.PB((Edge){x,y});for(i=0;i<S.size();i++) S[i].x>S[i].y&&(swap(S[i].x,S[i].y),0);
	Me(Ans,0x3f);for(i=1;i<=n;i++) Id.PB(i);scanf("%d",&m);for(i=1;i<=m;i++) scanf("%d%d",&x,&y),x^y?(G.PB((Ques){x,y,i}),0):(Ans[i]=0);sort(S.begin(),S.end(),cmp);Solve(S,G,Id);for(i=1;i<=m;i++) printf("%d\n",Ans[i]); 
}
posted @ 2022-07-09 18:17  275307894a  阅读(29)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end