[2021.8集训Day10/JZOJ.3441]【NOIP2013模拟】小喵喵的新家
题目
思路
线段树.
为了方便,我们将题目中提到的最小的扇形,即圆心角为\(\frac {2\pi}{2m}\)的扇形,叫做"单位扇形".
注意题目说的是:
她想知道有多大面积被至少铺过k次地毯
所以,我们把每一次操作,按照半径从大到小排序.依次枚举,当枚举到\(i\)时,一个"单位扇形"恰好被覆盖\(k\)次,不论后面再覆盖,这个半径为\(r_i\)单位扇形总会被算进答案.
我们把每一个单位扇形抽象成一个个区间,用线段树维护即可.
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
int read() {
int re = 0;
char c = getchar();
bool negt = false;
while(c < '0' || c > '9')
negt |= (c == '-') , c = getchar();
while(c >= '0' && c <= '9')
re = (re << 1) + (re << 3) + c - '0' , c = getchar();;
return negt ? -re : re;
}
int max(int a , int b) {
return a > b ? a : b;
}
const int inf = 0x3fffffff;
template <int ArraySize>
class SegmentTree {
#define ls(_) node[p].ls
#define rs(_) node[p].rs
private :
struct NodeClass {
int l , r , ls , rs , tag;
int maxnum , radius;
} node[ArraySize];
public :
int newnode () {
static int cnt = 0;
++cnt;
}
int build(int l , int r , int ori_data) {
int id = newnode();
node[id].l = l , node[id].r = r , node[id].maxnum = ori_data;
int mid = (l + r) / 2;
if(l == r)
return id;
node[id].ls = build(l , mid , ori_data);
node[id].rs = build(mid + 1 , r , ori_data);
return id;
}
void push_down(int p) {
if(node[p].tag != 0) {
node[ls(p)].maxnum += node[p].tag;
node[ls(p)].tag += node[p].tag;
node[rs(p)].maxnum += node[p].tag;
node[rs(p)].tag += node[p].tag;
node[p].tag = 0;
}
}
void change(int p , int l , int r , int radius) {
if(r < node[p].l || l > node[p].r)
return ;
if(node[p].maxnum == -1) {//加上这次覆盖后,有新的单位扇形被覆盖k次,不论区间是否全覆盖,强制下传,这里最多执行2m次,每次是log级别,不会超时
if(node[p].l == node[p].r)
node[p].radius = radius , node[p].maxnum = -inf;//为了方便,maxnum赋值无穷小
else {
push_down(p);
change(ls(p) , l , r , radius);
change(rs(p) , l , r , radius);
node[p].maxnum = max(node[ls(p)].maxnum , node[rs(p)].maxnum);
}
return;
}
if(l <= node[p].l && r >= node[p].r) {
node[p].maxnum += 1 , node[p].tag += 1;
return ;
}
push_down(p);
change(ls(p) , l , r , radius);
change(rs(p) , l , r , radius);
node[p].maxnum = max(node[ls(p)].maxnum , node[rs(p)].maxnum);
}
int query_radius(int p , int pos) {
if(node[p].l == node[p].r)
return node[p].radius;
int mid = (node[p].l + node[p].r) / 2;
push_down(p);
return pos <= mid ? query_radius(ls(p) , pos) : query_radius(rs(p) , pos);
}
int query_maxnum(int p , int pos) {
if(node[p].l == node[p].r)
return node[p].maxnum;
int mid = (node[p].l + node[p].r) / 2;
push_down(p);
return pos <= mid ? query_maxnum(ls(p) , pos) : query_maxnum(rs(p) , pos);
}
#undef ls
#undef rs
};
typedef long long lint ;
const int N = 200000 , M = 100000;
struct Draw {
int s , t , r;
} d[N + 10];
bool cmp(Draw a , Draw b) {
return a.r > b.r;
}
int n , m , k;
int root;
SegmentTree <M * 2 * 4 + 10> SegT;
signed main() {
// freopen("data//newhome13.in" , "r" , stdin);
n = read() , m = read() , k = read();
int n1 = n;
for(int i = 1 ; i <= n ; i++) {
d[i].r = read() , d[i].s = read() , d[i].t = read();
if(d[i].s < d[i].t)
d[i].s += m , d[i].t += m - 1;
else {
++n1;
d[n1].r = d[i].r , d[n1].s = -m + m , d[n1].t = d[i].t + m - 1;
d[i].s += m , d[i].t = m + m - 1;
}
}
n = n1;
std::sort(d + 1 , d + n + 1 , cmp);
root = SegT.build(0 , m * 2 , -k);
for(int i = 1 ; i <= n ; i++) {
if(d[i].s <= d[i].t)
SegT.change(root , d[i].s , d[i].t , d[i].r);
}
lint ans = 0;
for(int i = 0 ; i < m * 2 ; i++) {
lint r = SegT.query_radius(root , i);
ans += r * r ;
// std::cout << SegT.query_radius(root , i) << '\n';
}
std::cout << ans;
return 0;
}