[HAOI2011]防线修建

时间:2020-05-06
本文章向大家介绍[HAOI2011]防线修建,主要包括[HAOI2011]防线修建使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

\(\color{red}{为了护眼和更好的阅读体验,请您按住Ctrl键+滚轮将页面放大至120\%。QwQ}\)

洛谷链接

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


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

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

每次加入一个点,首先需要考虑它是否在凸包中,如果在就 \(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;
}

原文地址:https://www.cnblogs.com/clever-sheep/p/12837845.html