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;
}

浙公网安备 33010602011771号