peiwenjun's blog 没有知识的荒原

CF815D Karen and Cards 题解

题目描述

给定三维空间中的 \(n\) 个点 \((x_i,y_i,z_i)\)

求有多少个整点 \((x,y,z)\) 满足 \(1\le x\le p,1\le y\le q,1\le z\le r\) ,并且 \(\forall 1\le i\le n\)\([x\gt x_i]+[y\gt y_i]+[z\gt z_i]\ge 2\)

数据范围

  • \(1\le n,p,q,r\le 5\cdot 10^5,1\le x_i\le p,1\le y_i\le q,1\le z_i\le r\)

时间限制 \(\texttt{2s}\) ,空间限制 \(\texttt{512MB}\)

分析

固定 \(x\) ,统计怎样的 \((y,z)\) 会对答案产生贡献。

将所有点分为两类:

  • \(x\le x_i\) :限制 \(y\gt y_i\and z\gt z_i\)
  • \(x\gt x_i\) :限制 \(y\gt y_i\or z>z_i\)

第一类限制容易解决,将 \(y,z\) 的限制关于 \(x\) 做一个后缀 \(\max\) 即可,记为 \(ly_x,lz_x\)

\(mx_y\) 为满足 \(y_i\ge y\) 的所有第二类限制中的点, \(z_i\) 的最大值。

固定 \(y\) ,限制等价于 \(z\gt\max(mx_y,lz_{x})\) ,有 \(r-\max(mx_y,lz_x)\) 个点符合要求。

注意到第一类限制严格强于第二类限制,因此计算 \(mx\) 时,可以将第一类限制的点放进来,这样 \(mx\) 数组对所有的\(x\)都一样,可以预处理。

目标转化为求 \(\sum_{x=1}^p\sum_{y=ly_x+1}^q\big(r-max(mx_y,lz_x)\big)\)

从小到大枚举 \(x\) ,那么 \(ly_x,lz_x\) 逐渐变小,维护内层求和的答案。

由于 \(mx_y\) 随着 \(y\) 增大而减小,相当于右上角有一个阶梯状网格图,维护网格图与右上角矩形(初始为空)的交集大小。

用两个指针记录右上边界,增量可以 \(\mathcal O(1)\) 维护。

时间复杂度 \(\mathcal O(n+p+q+r)\)

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+5;
int n,p,q,r;
long long cur,res;
int ly[maxn],lz[maxn],mx[maxn],nx[maxn];
inline int read()
{
    int q=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) q=10*q+ch-'0',ch=getchar();
    return q;
}
inline void chmax(int &x,int y)
{
    if(x<=y) x=y;
}
int main()
{
    scanf("%d%d%d%d",&n,&p,&q,&r);
    for(int i=1;i<=n;i++)
    {
        int x=read(),y=read(),z=read();
        chmax(ly[x],y),chmax(lz[x],z),chmax(mx[y],z);
    }
    for(int x=p;x>=1;x--) chmax(ly[x],ly[x+1]),chmax(lz[x],lz[x+1]);
    for(int y=q;y>=1;y--) chmax(mx[y],mx[y+1]);
    for(int y=q;y>=1;y--) for(int i=mx[y];i>mx[y+1];i--) nx[i]=y;
    for(int x=1,y=q,z=r;x<=p;x++)
    {
        while(y>ly[x]) cur+=r-max(mx[y--],z);
        while(z>lz[x]) cur+=q-max(nx[z--],y);
        res+=cur;
    }
    printf("%lld\n",res);
    return 0;
}

posted on 2023-06-13 15:41  peiwenjun  阅读(13)  评论(0)    收藏  举报

导航