[2021.8集训Day10/JZOJ.3441]【NOIP2013模拟】小喵喵的新家

[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;
}
posted @ 2021-08-20 21:02  追梦人1024  阅读(35)  评论(0编辑  收藏  举报