我极度推荐去Luogu交,完全不要管什么UOJ
【码力提高题|UOJ#57./bzoj3051 【WC2013】(平面图转对偶图)】平面图转对偶图
这个实现。。。太恶心了。
1:其实从每条边开始走最左转线,是不会走到别的平面的边上的,第一次走到走过的边一定是开始的那条边。
2:找最左转线的时候可以把每个点出发的边按极角排序,找下一条边就是找当前边的反向边的同出发点的极角更小的第一条边。
3:因为平面图的边不会在中途相交,在中途我们可以用set维护斜率和截距(斜率为无限大的不需要考虑)
4:set插入时会返回一个pair,first装的是迭代器,存起来,删除可以删迭代器。。。。(我的精度啊。。。。。)
5:UOJ的hack数据并没有按照题面说的来。。。。。。还卡精度(计算几何的1e9.。。。。。)
6:对偶图不算无限区域可能不联通。。。。
7:改着改着就6KB了。
#include
#define maxn 600005
#define eps 1e-8
#define eps2 1e-10
#define eps3 1e-10
using namespace std;
inline int dcmp(double x)
{
if(x < -eps) return -1;
if(x > eps) return 1;
return 0;
}
inline int dcmp2(double x)
{
if(x < -eps2) return -1;
if(x > eps2) return 1;
return 0;
}
inline int dcmp3(double x)
{
if(x < -eps3) return -1;
if(x > eps3) return 1;
return 0;
}int n,m,q;
int u[maxn<<1],v[maxn<<1],h[maxn<<1],id[maxn<<1];
int bl[maxn<<1],cnt_bl,infarea;
double alp[maxn<<1];
bool cmp1(const int &u,const int &v){ return dcmp2(alp[u]-alp[v])==0?uG[maxn];
int rk[maxn];
int loc[maxn];
struct Query
{
Point A;
int id;
bool operator <(const Query &B)const{ return dcmp(A.x-B.A.x) == 0 ? id < B.id : A.x < B.A.x;
}
}Q[maxn];
double nowx;
struct Line
{
double k,b;
int id;
Line(double k=0,double b=0,int id=0):k(k),b(b),id(id){}
bool operator <(const Line &B)const
{
double a1 = k * nowx + b , a2 = B.k * nowx + B.b;
return dcmp3(a1-a2) == 0 ? dcmp2(k-B.k) == 0 ? id < B.id : k < B.k : a1 < a2;
}
};
Line calc(Point a,Point b,int id)
{
double k = (b.y-a.y)/(b.x-a.x) , B = a.y-k*a.x;
return Line(k,B,id);
}setst;
set::iterator it;
struct edg
{
int x,y,w;
edg(int x=0,int y=0,int w=0):x(x),y(y),w(w){}
bool operator <(const edg &B)const
{
return w==B.w ? x==B.x ? y < B.y : x < B.x : w < B.w;
}
}edge[maxn];
int info[maxn],Prev[maxn<<1],to[maxn<<1],cst[maxn<<1],cnt_e;
void Node(int u,int v,int ct){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cst[cnt_e]=ct;
}#define lim 18
int f[lim][maxn],g[lim][maxn],dep[maxn];
void dfs(int now,int ff)
{
dep[now] = dep[f[0][now] = ff] + 1;
for(int i=info[now];
i;
i=Prev[i])
if(to[i]!=ff)
g[0][to[i]]=cst[i],dfs(to[i],now);
}int F[maxn];
int Find(int now){ return !F[now] ? now : F[now] = Find(F[now]);
}int solve(int a,int b)
{
if(a == infarea|| b == infarea || Find(a)!=Find(b)) return -1;
int ret = 0;
if(dep[a] < dep[b]) swap(a,b);
for(int i=0;
dep[a]!=dep[b];
i++)
if((dep[a]-dep[b])>>i&1)
ret=max(ret,g[i][a]),a=f[i][a];
if(a == b) return ret;
for(int i=lim-1;
i>=0;
i--)
if(f[i][a]!=f[i][b])
ret=max(ret,max(g[i][a],g[i][b])),a=f[i][a],b=f[i][b];
ret = max(ret,max(g[0][a],g[0][b]));
return ret;
}set::iterator IT[maxn];
void cl(double &A)
{
double B = round(A);
if(B > A) A = B - 0.5;
else A = B + 0.5;
}int main()
{
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;
i<=n;
i++) scanf("%lf%lf",&P[i].x,&P[i].y);
for(int i=1;
i<=m;
i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
u[i<<1] = a , v[i<<1] = b , h[i<<1] = c,
id[i<<1]=i<<1 , alp[i<<1] = atan2(P[b].y-P[a].y,P[b].x-P[a].x);
u[i<<1|1] = b , v[i<<1|1] = a, h[i<<1|1] = c,
id[i<<1|1]=i<<1|1 , alp[i<<1|1] = atan2(P[a].y-P[b].y,P[a].x-P[b].x);
}
sort(id+2,id+2*m+2,cmp1);
for(int i=2;
i<=2*m+1;
i++)
{
int p = id[i];
rk[p] = G[u[p]].size();
G[u[p]].push_back(p);
}
for(int i=2;
i<=2*m+1;
i++)
{
if(!bl[i])
{
int eid = i , x , st = u[eid];
double area = 0;
for(++cnt_bl;
!bl[eid];
)
{
area += (P[u[eid]] - P[st]) * (P[v[eid]] - P[st]);
bl[eid] = cnt_bl;
x = v[eid] , eid = eid ^ 1;
if(rk[eid] == 0) eid = G[x].back();
else eid = G[x][rk[eid]-1];
}
if(area < 0) infarea = cnt_bl;
}
//if(n == 50002)
// printf("%d\n",bl[i]);
} for(int i=1;
i<=n;
i++) id[i] = i;
sort(id+1,id+1+n,cmp2);
scanf("%d",&q);
for(int i=1;
i<=q;
i++)
{
scanf("%lf%lf",&Q[i<<1].A.x,&Q[i<<1].A.y),Q[i<<1].id=i<<1;
scanf("%lf%lf",&Q[i<<1|1].A.x,&Q[i<<1|1].A.y),Q[i<<1|1].id=i<<1|1;
cl(Q[i<<1].A.x);
cl(Q[i<<1].A.y);
cl(Q[i<<1|1].A.x);
cl(Q[i<<1|1].A.y);
//if(n == 50002)
//{
// if(i == 17794)
//printf("%.3lf %.3lf\n",Q[i<<1].A.x,Q[i<<1].A.y);
//}
}
sort(Q+2,Q+2+2*q);
nowx = P[id[1]].x;
for(int i=2,j=1;
i<=2*q+1;
i++)
{
for(;
j<=n && dcmp(Q[i].A.x-P[id[j]].x)>=0;
j++)
{
int x = id[j];
for(int k=0,siz=G[x].size();
k;
k++)
{
int eid = G[x][k];
if(dcmp(P[u[eid]].x-P[v[eid]].x)!=0)
{
if(P[u[eid]].x > P[v[eid]].x)
st.erase(IT[eid^1]);
}
}
nowx = P[x].x + eps;
for(int k=0,siz=G[x].size();
k;
k++)
{
int eid = G[x][k];
if(dcmp(P[u[eid]].x-P[v[eid]].x)!=0)
{
if(P[u[eid]].x < P[v[eid]].x)
IT[eid] = st.insert(calc(P[u[eid]],P[v[eid]],eid)).first;
}
}
}
if(st.empty()){loc[Q[i].id] = infarea;
continue;
}
nowx = Q[i].A.x;
it = st.lower_bound(Line(0,Q[i].A.y,0));
// if(n==50002 && Q[i].id == (17794<<1))
//printf("%.3lf %.3lf %d\n",Q[i].A.x,Q[i].A.y,it == st.end());
if(it == st.end()) loc[Q[i].id] = infarea;
else if(it != st.begin())
{
it--;
if(dcmp3((*it).k*Q[i].A.x+(*it).b - Q[i].A.y) == 0)
loc[Q[i].id] = infarea;
loc[Q[i].id] = bl[(*it).id];
}
else loc[Q[i].id] = infarea;
}
for(int i=1;
i<=m;
i++)
{
edge[i] = edg(bl[i<<1],bl[i<<1|1],h[i<<1]);
//printf("%d %d %d\n",bl[i<<1],bl[i<<1|1],h[i<<1]);
}
sort(edge+1,edge+1+m);
for(int i=1;
i<=m;
i++)
{
if(edge[i].x == infarea || edge[i].y == infarea) continue;
if(Find(edge[i].x)!=Find(edge[i].y))
{
F[Find(edge[i].x)] = Find(edge[i].y);
Node(edge[i].x,edge[i].y,edge[i].w);
Node(edge[i].y,edge[i].x,edge[i].w);
}
} for(int i=1;
i<=cnt_bl;
i++)
if(!dep[i])
dfs(i,0);
for(int j=1;
j
推荐阅读
- 技术|为参加2021年蓝桥杯Java软件开发大学B组细心整理常见基础知识、搜索和常用算法解析例题(持续更新...)
- 笔记|C语言数据结构——二叉树的顺序存储和二叉树的遍历
- C语言学习(bit)|16.C语言进阶——深度剖析数据在内存中的存储
- 数据结构和算法|LeetCode 的正确使用方式
- 先序遍历 中序遍历 后序遍历 层序遍历
- 数据结构|C++技巧(用class类实现链表)
- 数据结构|贪吃蛇代码--c语言版 visual c++6.0打开
- 算法|算法-二分查找
- 数据结构学习指导|数据结构初阶(线性表)
- leetcode题解|leetcode#106. 从中序与后序遍历序列构造二叉树