把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

P3997 [SHOI2013] 扇形面积并

题意

给定 n 个同心的扇形,求有多少面积,被至少 \(k\) 个扇形所覆盖。

对于 \(100\%\) 的数据,\(1\leq n\leq 10^5\), \(1\leq m\leq 10^6\), \(1\leq k\leq 5000\), \(1\leq r_i\leq 10^5\),\(-m\leq a_1,a_2\leq m\)

分析

题目把 \((-\pi,\pi]\) 均匀分成了 \(2m\) 份,于是每一份的角度为 \(\frac{\pi}m\)

把这个扇形刻画成线段,\(r\) 就相当于高度,那么对于一个高度而言,若它要被计入答案,贡献就为:\(\frac{1}{2}R^2\frac{\pi}{m}=\frac{1}{2m}R^2\)

于是问题就转化成求一段可以找到第 \(k\) 大的半径(高度),计入它的平方和。

一般考虑权值线段树+扫描线,但是注意到 \(m\leq 10^6\),所以我们直接搞个桶就可以了。(如果不是的话,那只能用动态开点)。

代码

#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
#define int long long
#define N 2000006
using namespace std;
int n,m,k,tr[N],a1,a2,r;
vector<int> p[N];
void update(int x,int val) {
	for (;x < N;x += x & -x) tr[x] += val;
}
signed main(){
	cin >> n >> m >> k;
	for (int i = 1;i <= n;i ++){
		scanf("%lld%lld%ld",&r,&a1,&a2);
		if (a1 > a2) p[0].push_back(r);
		p[a1 + m].push_back(r);
		p[a2 + m].push_back(-r);
	}
	int cnt = 0,ans = 0;
	for (int i = 0;i < 2 * m;i ++) {
		for (auto j : p[i]) update(abs(j),j / abs(j)),cnt += j / abs(j);
		int u = 0,s = 0;
		if (cnt >= k) {
			for (int j = 21;j >= 0;j --)
				if (u + (1 << j) < N && s + tr[u + (1 << j)] < cnt - k + 1) s += tr[u += 1 << j];//跟lca的倍增一样(但是第k大需要像这样转变)
			ans += (u + 1) * (u + 1);
		}
	}
	cout << ans;
	return 0;
}
posted @ 2026-07-15 21:24  high_skyy  阅读(4)  评论(0)    收藏  举报
动态线条
动态线条end
浏览器标题切换
浏览器标题切换end
💬 加载中……