• [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
    ",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
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    2019年9月25日星期三(STM32 ucos3)
    2019年9月23日星期一(STM32 spi接口 rc522)
    2019年9月21日星期六(STM32 spi接口flash)
    2019年9月20日星期五(STM32 flash)
    2019年9月19日星期四(STM32 rtc实时时钟 i2c协议)
    2019年9月18日星期三(STM32 adc转换)
    2019年9月17日星期二(STM32 串口 看门狗)
    2019年9月16日星期一(STM32 串口 超声波 单总线通讯)
    2019年9月12日星期四(STM32 pwm 串口 )
    Win7/8/8.1系统中针对SSD需要禁用和改动的服务(转)
  • 原文地址:https://www.cnblogs.com/clever-sheep/p/12837845.html
Copyright © 2020-2023  润新知