CF815DKaren and Cards 单调栈+扫描线

Posted CQzhangyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF815DKaren and Cards 单调栈+扫描线相关的知识,希望对你有一定的参考价值。

【CF815D】Karen and Cards

题意:一张卡片有三个属性a,b,c,其上限分别为A,B,C,现在有n张卡片,定义一张卡片能打败另一张卡片当且仅当它的至少两项属性要严格大于另一张的对应属性。问在所有可能的卡片中,有多少种能打败这全部n张卡。

n,A,B,C<=500000

题解:我们反过来,统计哪些卡片不能打败全部的卡。

我们先确定一个属性c,那么对于某张卡片(ai,bi,ci),如果c<=ci,则要求!(a>ai&&b>bi);如果c>ci,则要求a<=ai&&b<=bi。这两种情况都可以用平面上的两个矩形来表示。

那么我们要做的就是动态维护这些矩形的并,发现矩形的并一定越来越小,反过来就是越来越大,我们用单调栈预处理一下,然后用扫描线统计即可。

#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=500010;
typedef long long ll;
ll ans,sum;
int n,A,B,C,top,tx,ty;
struct node
{
	int a,b,c;
}p[maxn];
int st[maxn],x[maxn],y[maxn];
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)	f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+(gc^‘0‘),gc=getchar();
	return ret*f;
}
bool cmpa(const node &a,const node &b)
{
	return a.a<b.a;
}
bool cmpc(const node &a,const node &b)
{
	return a.c>b.c;
}
int main()
{
	n=rd(),A=rd(),B=rd(),C=rd();
	int i,j;
	for(i=1;i<=n;i++)	p[i].a=rd(),p[i].b=rd(),p[i].c=rd();
	sort(p+1,p+n+1,cmpa);
	for(i=1;i<=n;i++)
	{
		while(top&&p[i].b>p[st[top]].b)	top--;
		st[++top]=i;
	}
	sum=1ll*A*B,st[top+1]=0;
	for(i=1;i<=top;i++)
	{
		sum-=1ll*(p[st[i]].a-p[st[i-1]].a)*p[st[i]].b;
		for(j=p[st[i-1]].a+1;j<=p[st[i]].a;j++)	y[j]=p[st[i]].b;
		for(j=p[st[i]].b;j>p[st[i+1]].b;j--)	x[j]=p[st[i]].a;
	}
	sort(p+1,p+n+1,cmpc);
	for(tx=ty=j=1,i=C;i;i--)
	{
		for(;j<=n&&p[j].c>=i;j++)
		{
			for(;tx<=p[j].a;tx++)	sum-=B-max(y[tx],ty-1);
			for(;ty<=p[j].b;ty++)	sum-=A-max(x[ty],tx-1);
		}
		ans+=sum;
	}
	printf("%lld",ans);
	return 0;
}

以上是关于CF815DKaren and Cards 单调栈+扫描线的主要内容,如果未能解决你的问题,请参考以下文章

CF815C Karen and Supermarket

Codeforces 781E Andryusha and Nervous Barriers 线段树 单调栈

CF1172A Nauuo and Cards 贪心

题解 CF546C Soldier and Cards

[CF743E] Vladik and cards

CF 1173C Nauuo and Cards