zoukankan      html  css  js  c++  java
  • [CEOI2020 D1T2 / CF1402B] 道路Roads 题解

    我的CEOI作战记录&题解-洛谷博客

    我的CEOI作战记录&题解-cnblogs

    题目链接-luogu 题目链接-Codeforces


    计算几何扫描线题.

    首先为了防止出现一些边界情况,(比如有一条无斜率的线段),可以把点转一个角度。

    用set维护当前的所有线段,并记录每条线段上方,最晚被插入/删除的后继的线段。

    然后从左到右扫描线,

    在每次加入线段的时候,考虑把加入的线段的左端点和set里的一个点连接起来。

    考虑这个线段在set上的前驱,如果前驱上记录了点,那我就把这个点和记录的点连起来,否则我就和前驱这条线段的左端点连起来。 同时用当前这条线段的左端点来更新前驱记录的点。

    在每次删除点的时候,更新一下set上的前驱记录的点即可。

    复杂度(O(n log n).)

    代码 :

    #define db long double
    const int N = 100050;
    db Pi = acos(-1.0),theta = Pi * (1.0 * 139 / 180),cost = cos(theta),sint = sin(theta);
    struct point{
    	db x,y; int realx,realy;
    	inline void calc(){ x = cost * realx - sint * realy,y = cost * realy + sint * realx; }
    }p[N<<1]; int n;
    inline void print(point a,point b){
    	cout << a.realx << ' ' << a.realy << ' ' << b.realx << ' ' << b.realy << '
    ';
    }
    struct Event{
    	int id,tp; db x;
    	bool operator < (Event w) const{ return x < w.x; }
    }ev[N<<1];
    db T;
    struct line{
    	int s,t; mutable int lst; db k,b;
    	inline void calc(){ k = (p[s].y - p[t].y) / (p[s].x - p[t].x),b = p[s].y - k * p[s].x; }
    	bool operator < (const line w) const{ return k*T+b < w.k*T+w.b; }
    }tmp;
    set<line>S; set<line>::iterator it;
    int main(){
    	int i;
    	ios::sync_with_stdio(0);
    	cin >> n;
    	for (i = 1; i <= n*2; i += 2){
    		cin >> p[i].realx >> p[i].realy,p[i].calc();
    		cin >> p[i+1].realx >> p[i+1].realy,p[i+1].calc();
    		if (p[i].x > p[i+1].x) swap(p[i],p[i+1]);
    		ev[i].id = i,ev[i].tp = 1,ev[i].x = p[i].x;
    		ev[i+1].id = i+1,ev[i+1].tp = 0,ev[i+1].x = p[i+1].x;
    	}
    	sort(ev+1,ev+(n<<1|1));
    	tmp.s = -2,tmp.t = tmp.lst = 0,tmp.k = 0,tmp.b = -1e10; S.insert(tmp);
    	tmp.s = -1,tmp.t = tmp.lst = 0,tmp.k = 0,tmp.b = 1e10; S.insert(tmp);
    	for (i = 1; i <= n*2; ++i){
    		T = ev[i].x;
    		if (ev[i].tp){
    			tmp.lst = tmp.s = ev[i].id,tmp.t = ev[i].id+1,tmp.calc();
    			it = S.insert(tmp).first,--it;
    			if (it->lst) print(p[it->lst],p[tmp.s]); it->lst = tmp.s;
    		}
    		else{
    			tmp.s = ev[i].id-1,tmp.t = ev[i].id,tmp.calc(),it = S.find(tmp),--it;
    			it->lst = tmp.t,S.erase(tmp);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    清理一瓶花茶中的虫子
    一些网上的新信息安全问题
    对于秋季高程备课的随笔
    用共享单车第一次遇到程序出现问题的思考
    开始带学生的一些感受
    对近期北辰开会的一些总结
    WSN和RFID书上好多问题:关于S50
    统计课设成绩用到excel画成绩频率分布曲线
    linux 常用命令
    局域网 ARP 欺骗原理详解
  • 原文地址:https://www.cnblogs.com/s-r-f/p/13591167.html
Copyright © 2011-2022 走看看