[差分约束][线段树][前缀和] Jzoj P3441 小喵喵的新家

Description

小喵喵和小聪聪从小就是好朋友 ,他们经常在一起玩耍 。如今小喵已经厌倦了自己居住的环境,想请小聪聪为她建一个新家。

小喵喵天生多才多艺,对多种乐器颇有研究。对于生活中常见的图形,她对圆形很感兴趣,因此小聪聪决定为她建一个圆形的新家。

我们设新家在一个平面直角坐标系上,其中新家的圆心为平面直角坐标系的原点。

小聪聪有一把神奇的剪刀,他定义了一个值m,以等分 [−pi,pi]弧度 (详见样例)。他还有一支神奇的画笔,将进行 n次“铺地毯”操作。对于第i 次“铺地毯”操作,他将设定一个半径ri,起始位置si,终止位置ti ,然后从圆心角pi*si/m到圆心角pi*ti/m这部分区域逆时针铺上一个扇形地毯。

小喵喵想到了一个奇怪的问题,她想知道有多大面积被至少铺过k次地毯。 这个问题一下就难倒了聪明的小聪聪。 现在小聪聪求助于你,你能帮他解决这个问题吗?为了方便表达 ,设答案的值为T,你只需要输出 T×2m/pi的值即可 。
 

Input

第一行是三个整数 n,m,k,含义 如题目描述中所述。

接下来n行, 每行描述一次铺地毯操作 。第i行有三个整数r,si,ti,含义 如 题目描述中所述。

Output

输出 一个整数 表示T×2m/pi的值。
 

Sample Input

3 8 2
1 -8 8
3 -7 3
5 -5 5

Sample Output

76
 

Data Constraint

 

Hint

题解

  • 对于60%的做法:
  • 前6个点,直接上暴力,别怂
  • 对于后6个点,所有的半径都是相同的,直接用差分约束思想,在扇形开始为1,结束为-1
  • 做一遍前缀和,然后将大于等于k的区间的长度求出来,算面积
  • 对于100%的做法:
  • 扇形的面积:(所占的份数/2m)*πr^2
  • 题目说:答案要乘一个2m/π
  • 这样一相乘 化简:所占份数*r^2
  • 就不用考虑精度问题啦!!!(出题人好评)
  • 现在就要求出所有被覆盖大于等于k的面积,半径就是第k大的半径
  • 那一个部分中有什么半径,我们怎么知道呢?
  • 我们把圆拆成一条线段,端点就是圆圈上的各个等分点
  • 把地毯的半径视为高,连接起始点和终点,如果有横跨线段中点的,把它看作两个部分
  • 样例如下图:(用denghan大爷一张图)
  • 这里写图片描述

  • 设g[r]为半径为r的数量
  • 我们可以从-m扫过去,碰到起始点的时候就把其对应的g[r]+1,碰到结束点的时候就把其对应的g[r]-1(也就类似与差分约束)

  • 现在就要求第k大值

  • 用线段树维护就好了

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 using namespace std;
 4 int n,m,k,r,s,t,cnt,p[500010],to[500010],head[200010],w[200010];
 5 long long ans;
 6 struct edge { int a,b,c; }e[500010];
 7 void insert(int x,int y) { e[++cnt].a=x; e[cnt].b=y; e[cnt].c=r; }
 8 int abs(int x) { return x<0?-x+100000:x; }
 9 void change(int l,int r,int d,int a,int b)
10 {
11     if (l==r) 
12     {
13         p[d]+=b;
14         return;
15     }
16     int mid=(l+r)/2;
17     if (a<=mid) change(l,mid,d*2,a,b); else change(mid+1,r,d*2+1,a,b);
18     p[d]=p[d*2]+p[d*2+1];
19 }
20 int find(int l,int r,int d,int k)
21 {
22     if (l==r) return p[d]>=k?l:0;
23     int mid=(l+r)/2;
24     return p[d*2+1]>=k?find(mid+1,r,d*2+1,k):find(l,mid,d*2,k-p[d*2+1]);
25 }
26 int main()
27 {
28     scanf("%d%d%d",&n,&m,&k);
29     for (int i=1;i<=n;i++)
30     {
31         scanf("%d%d%d",&r,&s,&t);
32         if (s==-m||s==m) insert(-m,1),insert(t,-1);
33         else
34         {
35             if (t==-m) t=m;
36             if (t>=s) insert(s,1),insert(t,-1);
37             else insert(s,1),insert(m,-1),insert(-m,1),insert(t,-1);
38         }
39     }
40     for (int i=1;i<=cnt;i++)
41     {
42         int j=abs(e[i].a);
43         if (!head[j]) head[j]=i; else to[w[j]]=i;
44         w[j]=i;
45     }
46     for (int i=-m;i<=m-1;i++)
47 
48     {
49         for (int j=head[abs(i)];j;j=to[j]) change(1,100000,1,e[j].c,e[j].b);
50         long long a=find(1,100000,1,k);
51         ans+=a*a;
52     }
53     printf("%lld",ans);
54     return 0;
55 }

猜你喜欢

转载自www.cnblogs.com/Comfortable/p/9338126.html
今日推荐