1. 程式人生 > 其它 >[2021.8集訓Day10/JZOJ.3441]【NOIP2013模擬】小喵喵的新家

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