zoukankan      html  css  js  c++  java
  • 【bzoj4418】[Shoi2013]扇形面积并 扫描线+线段树

    题目描述

    给定N个同心的扇形,求有多少面积,被至少K个扇形所覆盖。

    输入

    第一行是三个整数n,m,k。n代表同心扇形的个数,m用来等分 [-π,π]的弧度。
    从第二行开始的n行,每行三个整数r,a1,a2。描述了一个圆心在原点的扇形,半径为r,圆心角是从弧度πa1/m到πa2/m,a1可能大于a2,逆时针扫过的区域为该扇形面积。

    输出

    输出一个整数ans,至少被K个扇形所覆盖的总面积等于π/2m×ans
    保证答案不超过2^63-1

    样例输入

    【输入样例1】
    3 8 2
    1 -8 8
    3 -7 3
    5 -5 5
    【输入样例2】
    2 4 1
    4 4 2
    1 -4 4

    样例输出

    【输出样例1】
    76
    【输出样例2】
    98


    题解

    扫描线+线段树

    把每个扇形拆成:a1时刻加入扇形,a2时刻删除扇形。

    那么把所有这样的边放到一起,按照出现位置排序。

    然后问题转化为:前缀+1,前缀-1,查询值大于等于k的位置个数。容易发现数值是单调的,因此可以使用线段树维护修改,然后在线段树上二分解决问题。具体实现上,可以使用差分带点修改来代替区间修改。

    时间复杂度 $O(nlog n)$

    注意一下a1>a2时要拆成两个扇形(a1~m、-m~a2)解决。

    #include <cstdio>
    #include <algorithm>
    #define N 100010
    #define lson l , mid , x << 1
    #define rson mid + 1 , r , x << 1 | 1
    using namespace std;
    struct data
    {
    	int p , c , v;
    	data() {}
    	data(int P , int C , int V) {p = P , c = C , v = V;}
    	bool operator<(const data &a)const {return p < a.p;}
    }q[N << 2];
    int sum[N << 2] , tot;
    void update(int p , int a , int l , int r , int x)
    {
    	sum[x] += a;
    	if(l == r) return;
    	int mid = (l + r) >> 1;
    	if(p <= mid) update(p , a , lson);
    	else update(p , a , rson);
    }
    int query(int k , int l , int r , int x)
    {
    	if(l == r) return l;
    	int mid = (l + r) >> 1;
    	if(k < sum[x << 1]) return query(k , lson);
    	else return query(k - sum[x << 1] , rson);
    }
    int main()
    {
    	int n , m , k , i , a , b , r , last = 0 , now = 0;
    	long long ans = 0;
    	scanf("%d%d%d" , &n , &m , &k);
    	for(i = 1 ; i <= n ; i ++ )
    	{
    		scanf("%d%d%d" , &r , &a , &b);
    		if(a <= b) q[++tot] = data(a , r , 1) , q[++tot] = data(b , r , -1);
    		else q[++tot] = data(-m , r , 1) , q[++tot] = data(b , r , -1) , q[++tot] = data(a , r , 1) , q[++tot] = data(m , r , -1);
    	}
    	sort(q + 1 , q + tot + 1);
    	for(i = 1 ; i <= tot ; i ++ )
    	{
    		r = query(now - k , 1 , 100001 , 1) - 1 , ans += 1ll * r * r * (q[i].p - last);
    		now += q[i].v , update(q[i].c + 1 , q[i].v , 1 , 100001 , 1) , last = q[i].p;
    	}
    	printf("%lld
    " , ans);
    	return 0;
    }
    

     

  • 相关阅读:
    C语言II|博客园04
    C语言!!!博客作业03
    C语言II博客作业02
    C语言II—作业01
    deppin系统安装electron步骤及问题
    deppin20.2 频繁卡死问题已解决
    那些实用的Nginx规则
    hibernate4升级5带来的一些参数变化
    java 后台获取文件上传的真实扩展名
    eclipse 卡顿的优化办法
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/8010725.html
Copyright © 2011-2022 走看看