JZOJ-senior-5960. 【NOIP2018模拟11.8A组】小乔

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/HuangXinyue1017/article/details/83896242

Time Limits: 1000 ms Memory Limits: 524288 KB

Description

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

Input

在这里插入图片描述

Output

在这里插入图片描述

Sample Input

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

Sample Output

76
在这里插入图片描述

Data Constraint

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

Solution

很显然,这个图形可以被我们以某条线割开,拉出来变成一个线段上的问题,注意 s > t s>t 的情况
这就变成了平面图上的矩形覆盖问题,问覆盖次数不少于 k k 次的面积
矩形覆盖必须从最底往上,那下方覆盖的次数会比上方多,符合二分的性质
我们采用扫描线,对于左端,把它加入树状数组,右端,则删去左端标记
采用树状数组,对于每个位置,找出覆盖它次数刚好为 k k 的最外端并统计答案

Code

#include<algorithm>
#include<cstdio>

#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
#define ll long long

using namespace std;

const int N=5e5+5,R=5e5+5,inf=1e9;
int n,m,k,cnt,c[R+5];
struct node{int x,r,k;}a[2*N];

bool cmp(node x,node y)
{
	return x.x<y.x||x.x==y.x&&x.k>y.k;
}

void ins(int x,int y)
{
	while(x<=R) c[x]+=y,x+=x&(-x);
}

int sum(int x)
{
	if(!x) return inf;
	int s=0;
	while(x) s+=c[x],x-=x&(-x);
	return s;
}

int find()
{
	int l=0,r=R+1,out=0;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(sum(mid)>=k) out=max(out,mid),l=mid+1;
			else r=mid-1;
	}
	return out;
}

int main()
{
	freopen("xiaoqiao.in","r",stdin);
	freopen("xiaoqiao.out","w",stdout);
	scanf("%d%d%d",&n,&m,&k);
	fo(i,1,n)
	{
		int r,s,t;
		scanf("%d%d%d",&r,&s,&t);
		if(s<t)
		{
			a[++cnt]=(node){s,r,1};
			a[++cnt]=(node){t,r,-1};
		}
		if(s>t)
		{
			a[++cnt]=(node){s,r,1};
			a[++cnt]=(node){m,r,-1};
			a[++cnt]=(node){-m,r,1};
			a[++cnt]=(node){t,r,-1};
		}
	}
	sort(a+1,a+1+cnt,cmp);
	int i=1; ll ans=0;
	fo(line,-m,m)
	{
		int r=find();
		if(r<=R) ans=ans+(ll)r*r;
		while(i<=cnt&&a[i].x<=line)
		{
			if(a[i].k>0) ins(1,1),ins(a[i].r+1,-1);
				else ins(1,-1),ins(a[i].r+1,1);
			++i;
		}
	}
	printf("%lld",ans);
}

猜你喜欢

转载自blog.csdn.net/HuangXinyue1017/article/details/83896242
今日推荐