[2021.8集訓Day10/JZOJ.3441]【NOIP2013模擬】小喵喵的新家
阿新 • • 發佈:2021-08-20
目錄
[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; }