1. 程式人生 > >【CF815D】Karen and Cards 單調棧+掃描線

【CF815D】Karen and Cards 單調棧+掃描線

做的 int amp 預處理 family algorithm algo tchar esp

【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;
}

【CF815D】Karen and Cards 單調棧+掃描線