首页 > 其他分享 >【YBT2023寒假Day6 A】寄蒜挤河(计算几何)(线段树)

【YBT2023寒假Day6 A】寄蒜挤河(计算几何)(线段树)

时间:2023-02-07 19:33:40浏览次数:56  
标签:include return degree Day6 double ll YBT2023 寄蒜 now

寄蒜挤河

题目链接:YBT2023寒假Day6 A

题目大意

有一些二维平面上的点,按顺序加入,每次加入一个点后,问你图上有多少个三元点对使得它们构成的三角形严格包含原点,就是原点不能在点上或边上。

思路

发现直接按着求很难搞,似乎只能做到 \(n^2\) 之类的。
考虑转化一下,求不合法的方案数。

会发现其实不合法的条件是三个点跨越的极角不超过 \(180\degree\)。
(以原点在直线上的时候是 \(180\degree\) 为最大)

考虑每次插入一个 \(x\) 时候不合法方案的增加数。
考虑分别找到 \(x\) 顺时针逆时针 \(180\degree\) 范围极角差最大的点 \(y,z\)。
那一个方法就是枚举 \(y\sim x\) 里面的一个点 \(u\),然后另两个(这三个其中一个包括 \(x\))在 \(u\) 逆时针 \(180\degree\) 选。

分类讨论一下,如果 \(u\neq x\),那我们设 \(f_x\) 为 \(x\) 逆时针 \(180\degree\) 里面点的个数(不算 \(x\) 自己),那就是选一个 \(x\) 再选一个,就是 \(f_u\)。
如果 \(u=x\),那就是在旁边再选两个,就是 \(x\) 到 \(z\) 之间点的个数(算 \(z\) 不算 \(x\))\(d\) 的 \(\binom{d}{2}\)。

然后我们考虑维护 \(f_x\),其实很简单,每次加入 \(x\) 的时候把 \(y\sim x\) 极角范围内不包括 \(x\) 的点 \(f\) 值加一即可。
不过要注意你打标记不一定要加上去,要离散点,、之前已经放进来的点你再加(或者用平衡树也行,因为好像说原本打算出的是强制在线)

代码

#include<map>
#include<set>
#include<cmath>
#include<cstdio>
#include<algorithm>
#define ll long long

using namespace std;

const ll N = 4e5 + 100;
const double pi = acos(-1.0);
const double eps = 1e-11;
struct dian {
	ll x, y, id; double k;
}a[N], b[N];
ll n, dy[N];
double bk[N];
ll ans[N];

bool cmp(dian x, dian y) {
	return x.k < y.k;
}
bool cmp1(double x, double y) {
	return y - x > eps;
}

double Abs(double x) {return x < 0 ? -x : x;}
ll Abs(ll x) {return x < 0 ? -x : x;}

struct XD_tree {
	ll f[N << 2], lzy[N << 2];
	ll wkn[N << 2];
	
	void up(ll now) {
		f[now] = f[now << 1] + f[now << 1 | 1];
		wkn[now] = wkn[now << 1] + wkn[now << 1 | 1];
	}
	
	void downa(ll now, ll l, ll r, ll x) {
		lzy[now] += x;
		f[now] += x * wkn[now];
	}
	
	void down(ll now, ll l, ll mid, ll r) {
		if (lzy[now]) {
			downa(now << 1, l, mid, lzy[now]); downa(now << 1 | 1, mid + 1, r, lzy[now]);
			lzy[now] = 0;
		}
	}
	
	void mark(ll now, ll l, ll r, ll pl, ll x) {
		if (l == r) {
			wkn[now] = 1; f[now] = x;
			return ;
		}
		ll mid = (l + r) >> 1; down(now, l, mid, r);
		if (pl <= mid) mark(now << 1, l, mid, pl, x);
			else mark(now << 1 | 1, mid + 1, r, pl, x);
		up(now);
	}
	
	void update(ll now, ll l, ll r, ll L, ll R, ll x) {
		if (L > R) return ;
		if (L <= l && r <= R) {
			downa(now, l, r, x); return ;
		}
		ll mid = (l + r) >> 1; down(now, l, mid, r);
		if (L <= mid) update(now << 1, l, mid, L, R, x);
		if (mid < R) update(now << 1 | 1, mid + 1, r, L, R, x);
		up(now);
	}
	
	ll query(ll now, ll l, ll r, ll L, ll R) {
		if (L > R) return 0ll;
		if (L <= l && r <= R) return f[now];
		ll mid = (l + r) >> 1; down(now, l, mid, r); ll re = 0;
		if (L <= mid) re += query(now << 1, l, mid, L, R);
		if (mid < R) re += query(now << 1 | 1, mid + 1, r, L, R);
		return re;
	}
	
	ll queryn(ll now, ll l, ll r, ll L, ll R) {
		if (L > R) return 0;
		if (L <= l && r <= R) return wkn[now];
		ll mid = (l + r) >> 1; down(now, l, mid, r); ll re = 0;
		if (L <= mid) re += queryn(now << 1, l, mid, L, R);
		if (mid < R) re += queryn(now << 1 | 1, mid + 1, r, L, R);
		return re;
	}
}T;

int main() {
	freopen("geometry.in", "r", stdin);
	freopen("geometry.out", "w", stdout); 
	
	scanf("%lld", &n);
	for (ll i = 1; i <= n; i++) {
		scanf("%lld %lld", &a[i].x, &a[i].y); a[i].k = atan2(a[i].y, a[i].x); a[i].id = i; b[i] = a[i];
	}
	sort(b + 1, b + n + 1, cmp);
	for (ll i = 1; i <= n; i++) bk[i] = b[i].k;
	for (ll i = 1; i <= n; i++) dy[b[i].id] = i;
	
	ll ans = 0;
	for (ll i = 1; i <= n; i++) {
		ll now = dy[i];
		double k2 = a[i].k - pi; if (k2 <= -pi) k2 += 2 * pi;
		ll x = lower_bound(bk + 1, bk + n + 1, k2, cmp1) - bk;
		ll l = x, r = now - 1; if (l == n + 1) l = 1; if (r == 0) r = n;
		if (now != x) {
			if (l <= r) ans += T.query(1, 1, n, l, r), T.update(1, 1, n, l, r, 1);
				else ans += T.query(1, 1, n, l, n) + T.query(1, 1, n, 1, r), T.update(1, 1, n, l, n, 1), T.update(1, 1, n, 1, r, 1);
		}
		
		k2 = a[i].k + pi; if (k2 >= pi) k2 -= 2 * pi;
		x = upper_bound(bk + 1, bk + n + 1, k2, cmp1) - bk - 1;
		l = now + 1, r = x; if (l == n + 1) l = 1; if (r == 0) r = n; ll num = 0;
		if (now != x) {
			if (l <= r) num = T.queryn(1, 1, n, l, r);
				else num = T.queryn(1, 1, n, l, n) + T.queryn(1, 1, n, 1, r);
		}
		ans += 1ll * num * (num - 1) / 2;
		T.mark(1, 1, n, now, num);
		printf("%lld\n", 1ll * i * (i - 1) * (i - 2) / 6 - ans);
	}
	
	return 0;
} 

标签:include,return,degree,Day6,double,ll,YBT2023,寄蒜,now
From: https://www.cnblogs.com/Sakura-TJH/p/YBT2023Day6_A.html

相关文章

  • day67-sql中的事务
    事务要么都成功要么都失败事务原则:ACID原子性,一致性,隔离性,持久性原子性:要么一起成功要么一起失败一致性:针对一个事务操作前后状态一致持久性:事务结束后的数据不会随......
  • 20天零基础自学Python | Day6 运算符大全
    大家好,我是宁一。运算符是编程语言中最基本的知识点,是必须要掌握的,不仅适用于Python,其他编程语言也都能用到。1、算术运算符(1)加减乘除跟我们上学时学的都是一样的,注意乘法和......
  • 【YBT2023寒假Day5 C】路径计数(数学)(生成函数)
    路径计数题目链接:YBT2023寒假Day5C题目大意有一个h*w的网格,你要从左上角走到右下角,每次可以向右或者向下,定义一条路径的分数是它经过的位置的权值和。每次会选择权......
  • 【YBT2023寒假Day5 B】全面沦陷(tarjan)
    全面沦陷题目链接:YBT2023寒假Day5B题目大意给你一个有向图,问你有多少个点可以到达所有点。一个点x能到达一个点y当且仅当在原图有路径或在把边反向的图中有路径。......
  • day66 -收集表单数据
    收集表单数据<body><!--收集表单数据:若<inputtype="text"则v-model收集的是value值,用户输入的就是value若<inputtype="radio"则v-model收集的......
  • 【YBT2023寒假Day4 C】樱桃莓莓(交互)(四毛子分块)(线段树)
    樱桃莓莓题目链接:YBT2023寒假Day4C题目大意有一个黑盒操作满足交换律和结合律,有n个数,q次询问,每次选m个下标,你要计算所有不包含那m个下标的数进行黑盒操作之后的......
  • 【YBT2023寒假Day4 B】人人人数(数学)
    人人人数题目链接:YBT2023寒假Day4B题目大意随机生成一个长度为m且每个元素都是1~n的整数单调不降序列,问你这个序列的众数的期望出现次数是多少。(随机是所有满足条......
  • 【YBT2023寒假Day4 A】网格染色(DP)(矩阵乘法)(DFT)
    网格染色题目链接:YBT2023寒假Day4A题目大意有一个n*3的网格,你可以选恰好m个格子染成黑色。然后对于一个黑点,我们对它周围的\(8\)个点中的一些有限制不能是黑点,......
  • 【YBT2023寒假Day3 C】樱桃莓莓(凸包)(线段树)
    樱桃莓莓题目链接:YBT2023寒假Day3C题目大意给你一棵有根数,点有a,b两种权值。然后一个点的分数是它以及它所有祖先的a权值和的绝对值乘上b权值和的绝对值。然后......
  • 【YBT2023寒假Day3 A】千与千寻(期望DP)(高斯消元)
    千与千寻题目链接:YBT2023寒假Day3A题目大意一个n*m的平面,你要从(0,0)走到(x,y),你等概率的向上或向右走,然后当你走到(n-1,i)再往右走,就是(0,i),走到(i,m-1)再......