zoukankan      html  css  js  c++  java
  • 【bzoj2300】[HAOI2011]防线修建 离线+STL-set维护凸包

    题目描述

    给你(0,0)、(n,0)、(x,y)和另外m个点,除(0,0)(n,0)外每个点横坐标都大于0小于n,纵坐标都大于0。

    输入

    第一行,三个整数n,x,y分别表示河边城市和首都是(0,0),(n,0),(x,y)。
    第二行,一个整数m。
    接下来m行,每行两个整数a,b表示A国的一个非首都非河边城市的坐标为(a,b)。
    再接下来一个整数q,表示修改和询问总数。
    接下来q行每行要么形如1 i,要么形如2,分别表示撤销第i个城市的保护和询问。

    输出

    对于每个询问输出1行,一个实数v,表示修建防线的花费,保留两位小数

    样例输入

    4 2 1
    2
    1 2
    3 2
    5
    2
    1 1
    2
    1 2
    2

    样例输出

    6.47
    5.84
    4.47


    题解

    离线+STL-set维护凸包

    很容易想到离线,然后转变为加点,维护凸壳周长——经典的动态凸包问题。

    把所有凸包上的点按横坐标维护平衡树,插入一个点时,首先看它是否在凸包内。具体方法:找出其前驱后继的点,判断是否上凸。容易验证这样时正确的。

    然后考虑加入这个点,需要弹掉什么样的点:左边:找该点的前驱以及前驱的前驱,判断是否上凸,不上凸则弹掉前驱,否则停止。右边同理。

    由于一个点只被删除一次,因此时间复杂度时 $O(nlog n)$ 的。

    判断上凸可以使用叉积来判断。

    由于本题不需要在凸包上二分,因此平衡树只需要维护点坐标,使用STL-set即可。

    具体还是看代码吧。

    #include <set>
    #include <cmath>
    #include <cstdio>
    #define N 100010
    using namespace std;
    struct data
    {
    	int x , y;
    	data() {}
    	data(int a , int b) {x = a , y = b;}
    	bool operator<(const data &a)const {return x == a.x ? y < a.y : x < a.x;}
    	data operator-(const data &a)const {return data(x - a.x , y - a.y);}
    	int operator*(const data &a)const {return x * a.y - y * a.x;}
    	inline double calc() {return sqrt(x * x + y * y);}
    }a[N];
    set<data> s;
    int del[N] , opt[N << 1] , v[N << 1];
    double now , ans[N << 1];
    inline void modify(data p)
    {
    	data a , b;
    	set<data>::iterator it = s.lower_bound(p);
    	b = *it , a = *--it;
    	if((p - a) * (b - p) >= 0) return;
    	now -= (a - b).calc();
    	while(it != s.begin())
    	{
    		a = *it , b = *--it;
    		if((p - a) * (b - a) >= 0) now -= (a - b).calc() , s.erase(a);
    		else break;
    	}
    	it = s.lower_bound(p);
    	while(it != --s.end())
    	{
    		a = *it , b = *++it;
    		if((p - a) * (b - a) <= 0) now -= (a - b).calc() , s.erase(a);
    		else break;
    	}
    	it = s.lower_bound(p) , b = *it , a = *--it;
    	now += (p - a).calc() + (p - b).calc() , s.insert(p);
    }
    int main()
    {
    	int k , x , y , n , m , i;
    	scanf("%d%d%d%d" , &k , &x , &y , &n);
    	s.insert(data(0 , 0)) , s.insert(data(k , 0)) , s.insert(data(x , y)) , now = data(x , y).calc() + data(x - k , y).calc();
    	for(i = 1 ; i <= n ; i ++ ) scanf("%d%d" , &a[i].x , &a[i].y);
    	scanf("%d" , &m);
    	for(i = 1 ; i <= m ; i ++ )
    	{
    		scanf("%d" , &opt[i]);
    		if(opt[i] == 1) scanf("%d" , &v[i]) , del[v[i]] = 1;
    	}
    	for(i = 1 ; i <= n ; i ++ )
    		if(!del[i])
    			modify(a[i]);
    	for(i = m ; i ; i -- )
    	{
    		if(opt[i] == 1) modify(a[v[i]]);
    		else ans[i] = now;
    	}
    	for(i = 1 ; i <= m ; i ++ )
    		if(opt[i] == 2)
    			printf("%.2lf
    " , ans[i]);
    	return 0;
    }
    

     

  • 相关阅读:
    洛谷 P1194 飞扬的小鸟 题解
    洛谷 P1197 星球大战 题解
    洛谷 P1879 玉米田Corn Fields 题解
    洛谷 P2796 Facer的程序 题解
    洛谷 P2398 GCD SUM 题解
    洛谷 P2051 中国象棋 题解
    洛谷 P1472 奶牛家谱 Cow Pedigrees 题解
    洛谷 P1004 方格取数 题解
    洛谷 P2331 最大子矩阵 题解
    洛谷 P1073 最优贸易 题解
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/8075254.html
Copyright © 2011-2022 走看看