bzoj4418 [Shoi2013]扇形面积并

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4418

【题解】

被题目名称吓死系列。

用一棵线段树维护当前有哪些半径。

那么将扇形差分,每段空白区域相当于查询线段树内第K大。

权值线段树就行啦!

O(nlogn)

# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 5e5 + 10;
const int mod = 1e9+7;

# define RG register
# define ST static

int n, m, K;

struct pa {
    int r, pos;
    int f;
    pa() {}
    pa(int r, int pos, int f) : r(r), pos(pos), f(f) {}
    friend bool operator <(pa a, pa b) {
        return a.pos < b.pos;
    }
}p[M]; int pn = 0;

namespace SMT {
    int sz[M];
    # define ls (x<<1)
    # define rs (x<<1|1)
    inline void edt(int x, int l, int r, int pos, int del) {
        if(l == r) {
            sz[x] += del;
            return ;
        }
        int mid = l+r>>1;
        if(pos <= mid) edt(ls, l, mid, pos, del);
        else edt(rs, mid+1, r, pos, del);
        sz[x] = sz[ls] + sz[rs];
    }
    inline int query(int x, int l, int r, int rk) {
        if(l == r) return l;
        int mid = l+r>>1;
        if(sz[rs] < rk) return query(ls, l, mid, rk-sz[rs]);
        else return query(rs, mid+1, r, rk);
    }
    inline int query(int rk) {
        if(sz[1] < rk) return 0;
        else return query(1, 1, 1e5, rk);
    }    
}

int main() {
    cin >> n >> m >> K;
    for (int i=1, r, a1, a2; i<=n; ++i) {
        scanf("%d%d%d", &r, &a1, &a2);
        p[++pn] = pa(r, a1, 1);
        p[++pn] = pa(r, a2, -1);
        if(a1 > a2) {
            p[++pn] = pa(r, -m, 1);
            p[++pn] = pa(r, m, -1);
        }
    }
    ll ans = 0;
    int lst = -1e9;
    sort(p+1, p+pn+1);
//    for (int i=1; i<=pn; ++i) printf("pos = %d, r = %d, del = %d\n", p[i].pos, p[i].r, p[i].f);
    for (int i=1; i<=pn; ++i) {
        int ps = p[i].pos, j=i;
        if(lst != -1e9) {
            int R = SMT::query(K);// cout << p[i].pos << ' ' << R << endl;
            ans += 1ll * R * R * (p[i].pos - lst);
        }
        while(j+1 <= pn && p[j+1].pos == p[i].pos) ++j;
        for (int k=i; k<=j; ++k)
            SMT::edt(1, 1, 1e5, p[k].r, p[k].f);
        lst = p[i].pos;
        i = j;    
    }
    cout << ans;
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/galaxies/p/bzoj4418.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值