zoukankan      html  css  js  c++  java
  • P3268 [JLOI2016]圆的异或并

    题目链接

    两两不交?树形关系!

    但是暴力建树是 (O(n^2)) 的。如何优化建树?

    法一:K-D Tree 优化建树

    毕竟这是个二维问题,K-D Tree 最擅长搞了。然后我们会发现,这种方法只有70pts。不过也没必要吃惊,毕竟 K-D Tree 的复杂度本来就是 (O(玄学))

    法二:扫描线

    我们拿出远古时期(这里指五个月前)学过的算法:扫描线。从左向右扫,动态维护纵轴信息。

    由于题目保证圆圆不交,纵轴上的相对关系永远不变(除非扫过了某个圆)。而我们只需要知道新加的那个圆旁边(或者包住它的)那个圆的贡献类型即可。

    直接用 set 维护加入的圆,分上半圆(上括号)和下半圆(下括号),不过要重载运算符,需要比较的时候现场算纵坐标。对于每个新加的圆,我们查它的前驱(下驱)是不是上括号,据此判断贡献类型。

    值得注意的是,扫描线与圆相切的时候(题目保证圆圆不相切,但是扫描线肯定会与圆相切),可能会出一些奇奇怪怪的错误,因此我们最好在算纵坐标的时候根据类型加减 (eps),防止“相等”。

    还有,set 有一个非常好用的功能:(insert) 函数有一个 pair 类型的返回值,其中第一个是迭代器,第二个是插进去的值。这样我们就不用再 (lower_bound) 惹出事端。

    关键代码(tbl风格,因为我借鉴他的题解):

    struct cir {
    	int type, x, y, r, cur;
    	cir(int t = 0, int xx = 0, int yy = 0, int rr = 0, int curr = 0) { 
    		type = t, x = xx, y = yy, r = rr, cur = curr;
    	}
    	inline double gety() { return y + type * (sqrt(r * r - (x - nw) * (x - nw)) + eps);}
    }ci[N << 1];
    bool operator <(cir a, cir b) {
    	double t1 = a.gety(), t2 = b.gety();
    	return t1 - t2 < -eps;
    }
    PII pr[N << 1];
    set<cir> st;
    int Tp[N];//Attention!!!
    signed main() {
    	read(n);
    	for (register int i = 1; i <= n; ++i) {
    		int x, y, r; read(x), read(y), read(r);
    		ci[i] = cir(1, x, y, r, i);
    		ci[i + n] = cir(-1, x, y, r, i);
    	}
    	for (register int i = 1; i <= n; ++i)
    		pr[i] = MP(ci[i].x - ci[i].r, i), pr[i + n] = MP(ci[i].x + ci[i].r, i + n);
    	sort(pr + 1, pr + 1 + n + n);
    	for (register int i = 1; i <= n + n; ++i) {
    		int d = pr[i].second;
    		nw = pr[i].first;//Attention!!!!
    		if (d <= n) {
    			set<cir>::iterator it = st.insert(ci[d]).first;
    			if (it == st.begin())	Tp[d] = 1;
    			else {
    				--it;
    				int t = (*it).type;
    				if (t == 1)	Tp[d] = Tp[(*it).cur];
    				else	Tp[d] = -1 * Tp[(*it).cur];
    			}
    			st.insert(ci[d + n]);
    		} else {
    			d -= n;
    			st.erase(ci[d]); st.erase(ci[d + n]);
    		}
    	}
    	int ans = 0;
    	for (register int i = 1; i <= n; ++i)
    		ans += Tp[i] * ci[i].r * ci[i].r;
    	printf("%lld
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    docker使用常用命令:启动/重启/关闭docker
    golang 中内存模型
    【转】Linux fork操作之后发生了什么?又会共享什么呢?
    go检查channel是否关闭
    golang select case 用法
    【转】理解字节序 大端字节序和小端字节序
    【转】3种TCP连接异常的情况。
    react-window 多条列表数据加载(虚拟滚动)
    ts 中 interface 与 class 的区别
    js new一个对象的过程,实现一个简单的new方法
  • 原文地址:https://www.cnblogs.com/JiaZP/p/13449195.html
Copyright © 2011-2022 走看看