[HAOI2011]防线修建

洛谷链接

太懒了,懒得描述题面了。。。


凸包删点谁受得了,凸包就没法维护了,所以我们倒着看,把删点改为加点,每次加一个可能导致一些点从凸包上消失,但每个点消失一次就回不来了,所以每个点访问一次,可以保证复杂度。

还好这题是个壳不是个包,否则比较毒瘤了。

每次加入一个点,首先需要考虑它是否在凸包中,如果在就 return ,如果不考虑这个的话,可能这个点左边和右边确实维护成了凸壳,但是自己这个位置是凹的。然后向左看,将叉积小于 0 的中间点删除,向右看,将叉积大于 0 的中间点删除。

用一颗平衡树维护凸壳。由于博主太菜,set 用的不熟,怕那些奇奇怪怪的边界问题,所以手写了个 Splay,更灵活但是代码稍长点。

#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #define QWQ cout<<"QwQ"<<endl; #define ll long long #include <vector> #include <queue> #include <stack> #include <map> #define ls son[x][0] #define rs son[x][1] using namespace std; const int N=401010; const int qwq=303030; const int inf=0x3f3f3f3f; int R; int n,m; struct E{ double x,y; E(double xx=0,double yy=0) { x=xx; y=yy; } }val[N],a[N]; int root = 1,tot; int son[N][2],fa[N]; int cz[N],cx[N],vis[N]; double ANS,ans[N]; inline int read() { int lyy = 0, zbk = 1; char z7z = getchar(); while(z7z<'0' || z7z>'9') { if(z7z=='-') zbk = -1; z7z = getchar(); } while(z7z>='0'&&z7z<='9') { lyy = lyy * 10 + z7z - '0'; z7z = getchar(); } return lyy * zbk; } inline double cha(E aa,E bb,E cc) { E A = E(bb.x-aa.x,bb.y-aa.y), B = E(cc.x-bb.x,cc.y-bb.y); return A.x*B.y - A.y*B.x; } inline double ju(int aa,int bb) { E A = val[aa], B = val[bb]; return sqrt( (A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y) ); } inline bool touhou(int x) { return son[fa[x]][1]==x; } inline void rotate(int x) { int y = fa[x], z = fa[y], k = touhou(x), w = son[x][k^1]; son[z][touhou(y)] = x; son[x][k^1] = y; son[y][k] = w; fa[x] = z; fa[y] = x; fa[w] = y; } inline void Splay(int x,int goal) { while(fa[x] != goal) { int y = fa[x], z = fa[y]; if(z!=goal) { if(touhou(x)==touhou(y)) rotate(y); else rotate(x); } rotate(x); } if(!goal) root = x; } inline int qian(int x) { Splay(x,0); if(!ls) return -1; x = ls; while(rs) x = rs; return x; } inline int hou(int x) { Splay(x,0); if(!rs) return -1; x = rs; while(ls) x = ls; return x; } inline void del(int x) { int y = qian(x), z = hou(x); Splay(y,0); Splay(z,y); son[z][0] = fa[x] = 0; } void insert(E u) { int v = root, f; while(v) f = v, v = son[v][ val[v].x<u.x ]; v = ++tot; val[v] = u; fa[v] = f; son[f][ val[f].x<u.x ] = v; Splay(v,0); int lv = qian(v), rv = hou(v); if(cha(val[lv],val[v],val[rv])>=0) { del(v); return ; } ANS -= ju(lv,rv); ANS += ju(v,lv); ANS += ju(v,rv); while(2333) { int aa = qian(v), bb = qian(aa); if(bb==-1) break; if(cha(val[bb],val[aa],val[v])>=0) { ANS -= ju(aa,bb) + ju(aa,v); del(aa); ANS += ju(bb,v); } else break; } while(2333) { int aa = hou(v), bb = hou(aa); if(bb==-1) break; if(cha(val[v],val[aa],val[bb])>=0) { ANS -= ju(aa,bb) + ju(aa,v); del(aa); ANS += ju(bb,v); } else break; } } int main() { int x,y; R = read(); x = read(); y = read(); root = 1; fa[2] = fa[3] = 1; son[1][0] = 2; son[1][1] = 3; tot = 3; val[2] = E(0,0); val[3] = E(R,0); val[1] = E(x,y); ANS += ju(1,2); ANS += ju(1,3); n = read(); for(int i=1;i<=n;i++) a[i].x = read(), a[i].y = read(); m = read(); for(int i=1;i<=m;i++) { cz[i] = read(); if(cz[i]==1) { cx[i] = read(); vis[ cx[i] ] = 1; } } for(int i=1;i<=n;i++) if(!vis[i]) insert(a[i]); for(int i=m;i>=1;i--) { if(cz[i]==2) ans[i] = ANS; else insert(a[ cx[i] ]); } for(int i=1;i<=m;i++) if(cz[i]==2) printf("%.2lf\n",ans[i]); return 0; }

感觉考场上手敲平衡树很不吃香,所以看了别的大佬的题解重写了个 set 版的:

#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #define QWQ cout<<"QwQ"<<endl; #define ll long long #include <vector> #include <queue> #include <stack> #include <set> using namespace std; const int N=401010; const int qwq=303030; const int inf=0x3f3f3f3f; int n,m; int cz[N],cx[N],vis[N]; double ans[N],ANS; struct E{ int x,y; E(int xx=0,int yy=0) { x=xx; y=yy; } } a[N]; inline E operator - (E aa,E bb) { return E(aa.x-bb.x,aa.y-bb.y); } inline int operator * (E aa,E bb) { return aa.x*bb.y-aa.y*bb.x; } inline bool operator < (E aa,E bb) { return (aa.x==bb.x)?(aa.y<bb.y):(aa.x<bb.x); } set <E> S; inline int read() { int lyy = 0, zbk = 1; char z7z = getchar(); while(z7z<'0' || z7z>'9') { if(z7z=='-') zbk = -1; z7z = getchar(); } while(z7z>='0'&&z7z<='9') { lyy = lyy * 10 + z7z - '0'; z7z = getchar(); } return lyy * zbk; } inline double ju(E aa) { return sqrt(aa.x*aa.x+aa.y*aa.y); } inline void Push(E x) { set<E>::iterator r = S.lower_bound(x), l = r, mid; --l; if( (*l - x) * (*r - x) < 0) return; ANS -= ju(*r - *l); while(2333) { mid = r; ++r; if(r==S.end() || (*mid - x) * (*r - x) <= 0) break; ANS -= ju(*r - *mid); S.erase(mid); } while(2333) { mid = l; --l; if(mid==S.begin() || (*mid - *l) * (x - *l) <= 0) break; ANS -= ju(*mid - *l); S.erase(mid); } S.insert(x); l = r = S.find(x); --l; ++r; ANS += ju(x - *l) + ju(x - *r); } int main() { int R,X,Y; R = read(); X = read(); Y = read(); S.insert(E(0,0)); S.insert(E(R,0)); S.insert(E(X,Y)); ANS += ju( E(X,Y) ) + ju( E(X-R,Y) ); n = read(); for(int i=1;i<=n;i++) a[i].x = read(), a[i].y = read(); m = read(); for(int i=1;i<=m;i++) { cz[i] = read(); if(cz[i]==2) continue; cx[i] = read(); vis[cx[i]] = 1; } for(int i=1;i<=n;i++) if(!vis[i]) Push(a[i]); for(int i=m;i>=1;i--) { if(cz[i]==2) ans[i] = ANS; else Push(a[cx[i]]); } for(int i=1;i<=m;i++) if(cz[i]==2) printf("%.2lf\n",ans[i]); return 0; }

__EOF__

本文作者枫叶晴
本文链接https://www.cnblogs.com/maple276/p/12837845.html
关于博主:菜菜菜
版权声明:呃呃呃
声援博主:呐呐呐
posted @   maple276  阅读(100)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示