JZOJ5960. 【NOIP2018模拟11.8A组】小乔

18 篇文章 0 订阅
17 篇文章 0 订阅

在这里插入图片描述
在这里插入图片描述

题解

先考虑答案是什么,在每一个块
显然是每个块,最大的被覆盖了k次的半径的平方的和。
其实圆至少为了求答案二出的一个背景,
想像一下,将这个圆沿着某个半径切开,拉开成一个一个矩形。
那么一个覆盖操作就变成了一个矩形,
而现在也就是要求每一列,覆盖能被k次的最高高度。
用扫描线,树状数组维护每个位置被覆盖的次数。
因为每个位置覆盖次数都是从下往上是递减的,
于是可以二分。
具体做法,
将枚举矩形拆成两个操作,左边界加,右边界减。
然后对所有操作排序。
从左往右,枚举每一行,
用树状数组的前缀和来表示这个位置被覆盖了多少次,
二分一个答案,在树状数组里面查询。
所以总的时间复杂度是 O ( n l o g n 2 ) O(nlog_n^2) O(nlogn2)
要注意跨过分割半径的去拆成两个区间。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
char ch;
void read(int&n)
{
	int w=1;
	for(ch=getchar();(ch<'0' || ch>'9') && ch!='-';ch=getchar());
	if(ch=='-')w=-1,ch=getchar();
	for(n=0;'0'<=ch && ch<='9';ch=getchar())n=(n<<1)+(n<<3)+ch-48;
	n=n*w;
}
const int N=100003;
int n,m,k,l,r,mid,mxr;
int x,y,z,s[N],tot,id,t;
ll ans;
struct node
{
	int x,k,v;
}a[3*N];
bool cmp(node a,node b){return a.x<b.x;}
int x_(int x){return x&(-x);}
void ins(int x){for(int i=x;i<=mxr;i=i+x_(i))s[i]++;}
void ins_(int x){for(int i=x;i<=mxr;i=i+x_(i))s[i]--;}
int find(int x){int S=0;for(int i=x;i;i=i-x_(i))S=S+s[i];return S;}
int main()
{
	freopen("xiaoqiao.in","r",stdin);
	freopen("xiaoqiao.out","w",stdout);
	read(n);read(m);read(k);
	for(int i=1;i<=n;i++)
	{
		read(x);read(y);read(z);
		x++;mxr=(mxr>x?mxr:x);
		if(y<z)
		{
			tot++;a[tot].x=y,a[tot].k=x;a[tot].v=1;
			tot++;a[tot].x=z,a[tot].k=x;a[tot].v=-1;
		}
		else
		{
			tot++;a[tot].x=-m,a[tot].k=x;a[tot].v=1;
			tot++;a[tot].x=z,a[tot].k=x;a[tot].v=-1;
			tot++;a[tot].x=y,a[tot].k=x;a[tot].v=1;
		}
	}
	sort(a+1,a+1+tot,cmp);id=1;
	for(int i=-m;i<m;i++)
	{
		for(;id<=tot && a[id].x==i;id++)
			if(a[id].v==1)ins(1),ins_(a[id].k);else ins_(1),ins(a[id].k);
		t=0;
		for(l=0,r=mxr;l<r;)
		{
			mid=(l+r)>>1;
			if(find(mid)>=k)l=mid+1,t=mid;else r=mid;
		}
		if(find(l)>=k)t=max(t,l);
		ans=ans+(ll)t*t;
	}
	printf("%lld",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值